From dac98ef60a0f6db72f18b9404536be975bfe8c4c Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 27 Sep 2023 13:46:47 -0500 Subject: [PATCH 01/22] skip failing test suite (#166190) --- .../migrations/group3/actions/actions_test_suite.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts index bb509799c052d0..065ce179f480c3 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions_test_suite.ts @@ -756,7 +756,8 @@ export const runActionTestSuite = ({ // Reindex doesn't return any errors on it's own, so we have to test // together with waitForReindexTask - describe('reindex & waitForReindexTask', () => { + // Failing: See https://github.com/elastic/kibana/issues/166190 + describe.skip('reindex & waitForReindexTask', () => { it('resolves right when reindex succeeds without reindex script', async () => { const res = (await reindex({ client, From f3f1eec08e4808d36a7dc4294df4f917e454c883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20FOUCRET?= Date: Wed, 27 Sep 2023 21:11:46 +0200 Subject: [PATCH 02/22] Update content indices pipeline management UI with ELSER v2 (wording) (#167401) --- .../pipelines/ml_inference/deploy_model.tsx | 4 ++-- .../pipelines/ml_inference/model_deployed.tsx | 2 +- .../ml_inference/model_deployment_in_progress.tsx | 2 +- .../pipelines/ml_inference/model_started.tsx | 10 +++++----- .../text_expansion_callout_logic.test.ts | 14 +++++++------- .../ml_inference/text_expansion_callout_logic.ts | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx index 5431c7c41454cb..ef7dd486e5eb1e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/deploy_model.tsx @@ -55,7 +55,7 @@ export const DeployModel = ({

{i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.title', - { defaultMessage: 'Improve your results with ELSER' } + { defaultMessage: 'Improve your results with ELSER v2' } )}

@@ -73,7 +73,7 @@ export const DeployModel = ({ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx index fe8f0b7953c7d4..50d8ea47fb8f1f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployed.tsx @@ -51,7 +51,7 @@ export const ModelDeployed = ({

{i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployedTitle', - { defaultMessage: 'Your ELSER model has deployed but not started.' } + { defaultMessage: 'Your ELSER v2 model has deployed but not started.' } )}

diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx index f9b94398332559..8804f4ec584397 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_deployment_in_progress.tsx @@ -28,7 +28,7 @@ export const ModelDeploymentInProgress = ({

{i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.deployingTitle', - { defaultMessage: 'Your ELSER model is deploying.' } + { defaultMessage: 'Your ELSER v2 model is deploying.' } )}

diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx index 3c400854a5df0a..fa5a46d438041a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_started.tsx @@ -49,20 +49,20 @@ export const ModelStarted = ({ ? isCompact ? i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitleCompact', - { defaultMessage: 'Your ELSER model is running single-threaded.' } + { defaultMessage: 'Your ELSER v2 model is running single-threaded.' } ) : i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedSingleThreadedTitle', - { defaultMessage: 'Your ELSER model has started single-threaded.' } + { defaultMessage: 'Your ELSER v2 model has started single-threaded.' } ) : isCompact ? i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitleCompact', - { defaultMessage: 'Your ELSER model is running.' } + { defaultMessage: 'Your ELSER v2 model is running.' } ) : i18n.translate( 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedTitle', - { defaultMessage: 'Your ELSER model has started.' } + { defaultMessage: 'Your ELSER v2 model has started.' } )} @@ -91,7 +91,7 @@ export const ModelStarted = ({ 'xpack.enterpriseSearch.content.index.pipelines.textExpansionCallOut.startedBody', { defaultMessage: - 'Enjoy the power of ELSER in your custom Inference pipeline.', + 'Enjoy the power of ELSER v2 in your custom Inference pipeline.', } )}

diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts index e36b57d6ee1106..e39230ee2b69b7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.test.ts @@ -80,19 +80,19 @@ describe('TextExpansionCalloutLogic', () => { }); it('uses the correct title and message from a create error', () => { expect(getTextExpansionError(error, undefined, undefined)).toEqual({ - title: 'Error with ELSER deployment', + title: 'Error with ELSER v2 deployment', message: error.body?.message, }); }); it('uses the correct title and message from a fetch error', () => { expect(getTextExpansionError(undefined, error, undefined)).toEqual({ - title: 'Error fetching ELSER model', + title: 'Error fetching ELSER v2 model', message: error.body?.message, }); }); it('uses the correct title and message from a start error', () => { expect(getTextExpansionError(undefined, undefined, error)).toEqual({ - title: 'Error starting ELSER deployment', + title: 'Error starting ELSER v2 deployment', message: error.body?.message, }); }); @@ -303,7 +303,7 @@ describe('TextExpansionCalloutLogic', () => { describe('textExpansionError', () => { const error = { body: { - error: 'Error with ELSER deployment', + error: 'Error with ELSER v2 deployment', message: 'Mocked error message', statusCode: 500, }, @@ -318,21 +318,21 @@ describe('TextExpansionCalloutLogic', () => { it('returns extracted error for create', () => { CreateTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error with ELSER deployment', + title: 'Error with ELSER v2 deployment', message: 'Mocked error message', }); }); it('returns extracted error for fetch', () => { FetchTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error fetching ELSER model', + title: 'Error fetching ELSER v2 model', message: 'Mocked error message', }); }); it('returns extracted error for start', () => { StartTextExpansionModelApiLogic.actions.apiError(error); expect(TextExpansionCalloutLogic.values.textExpansionError).toStrictEqual({ - title: 'Error starting ELSER deployment', + title: 'Error starting ELSER v2 deployment', message: 'Mocked error message', }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts index e808e8cbf74403..e8e6913c38ce87 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/text_expansion_callout_logic.ts @@ -97,7 +97,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionCreateError.title', { - defaultMessage: 'Error with ELSER deployment', + defaultMessage: 'Error with ELSER v2 deployment', } ), message: getErrorsFromHttpResponse(createError)[0], @@ -107,7 +107,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionStartError.title', { - defaultMessage: 'Error starting ELSER deployment', + defaultMessage: 'Error starting ELSER v2 deployment', } ), message: getErrorsFromHttpResponse(startError)[0], @@ -117,7 +117,7 @@ export const getTextExpansionError = ( title: i18n.translate( 'xpack.enterpriseSearch.content.indices.pipelines.textExpansionFetchError.title', { - defaultMessage: 'Error fetching ELSER model', + defaultMessage: 'Error fetching ELSER v2 model', } ), message: getErrorsFromHttpResponse(fetchError)[0], From 594cb14a2811110b2edee247cd6e1276dcd095fc Mon Sep 17 00:00:00 2001 From: Jordan <51442161+JordanSh@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:35:03 +0300 Subject: [PATCH 03/22] [Cloud Security] Azure - AMR Template form (#166910) --- .../common/constants.ts | 6 + .../cloud_security_posture/common/types.ts | 6 + .../common/utils/helpers.ts | 7 + .../public/common/constants.ts | 7 +- .../azure_credentials_form.tsx | 238 ++++++++++++++++++ .../get_azure_credentials_form_options.tsx | 51 ++++ .../azure_credentials_form/hooks.ts | 176 +++++++++++++ .../csp_boxed_radio_group.tsx | 2 +- .../components/fleet_extensions/mocks.ts | 32 ++- .../policy_template_form.test.tsx | 51 +++- .../fleet_extensions/policy_template_form.tsx | 134 +++++++++- .../policy_template_selectors.tsx | 3 + .../components/fleet_extensions/utils.ts | 19 +- .../post_install_azure_arm_template_modal.tsx | 103 ++++++++ .../single_page_layout/hooks/form.tsx | 15 ++ .../single_page_layout/index.tsx | 9 + .../create_package_policy_page/types.ts | 1 + .../azure_arm_template_instructions.tsx | 73 ++++++ .../agent_enrollment_flyout/hooks.tsx | 52 +++- .../agent_enrollment_flyout/instructions.tsx | 1 + .../steps/compute_steps.tsx | 10 + .../agent_enrollment_flyout/steps/index.tsx | 1 + ..._azure_arm_template_managed_agent_step.tsx | 52 ++++ .../agent_enrollment_flyout/types.ts | 10 + .../components/azure_arm_template_guide.tsx | 72 ++++++ .../use_create_azure_arm_template_url.ts | 51 ++++ ...get_azure_arm_props_from_package_policy.ts | 32 +++ ...ion_template_url_from_package_info.test.ts | 66 ----- ...et_template_url_from_agent_policy.test.ts} | 59 ++++- ... => get_template_url_from_agent_policy.ts} | 19 +- ...get_template_url_from_package_info.test.ts | 112 +++++++++ ... => get_template_url_from_package_info.ts} | 17 +- x-pack/plugins/fleet/public/services/index.ts | 4 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 36 files changed, 1370 insertions(+), 124 deletions(-) create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx create mode 100644 x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_azure_arm_template_modal.tsx create mode 100644 x-pack/plugins/fleet/public/components/agent_enrollment_flyout/azure_arm_template_instructions.tsx create mode 100644 x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_azure_arm_template_managed_agent_step.tsx create mode 100644 x-pack/plugins/fleet/public/components/azure_arm_template_guide.tsx create mode 100644 x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts create mode 100644 x-pack/plugins/fleet/public/services/get_azure_arm_props_from_package_policy.ts delete mode 100644 x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.test.ts rename x-pack/plugins/fleet/public/services/{get_cloud_formation_template_url_from_agent_policy.test.ts => get_template_url_from_agent_policy.test.ts} (51%) rename x-pack/plugins/fleet/public/services/{get_cloud_formation_template_url_from_agent_policy.ts => get_template_url_from_agent_policy.ts} (66%) create mode 100644 x-pack/plugins/fleet/public/services/get_template_url_from_package_info.test.ts rename x-pack/plugins/fleet/public/services/{get_cloud_formation_template_url_from_package_info.ts => get_template_url_from_package_info.ts} (68%) diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index 7f0b4f62fb2165..23de4b6d02e36b 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -10,6 +10,7 @@ import { VulnSeverity, AwsCredentialsTypeFieldMap, GcpCredentialsTypeFieldMap, + AzureCredentialsTypeFieldMap, } from './types'; export const STATUS_ROUTE_PATH = '/internal/cloud_security_posture/status'; @@ -156,3 +157,8 @@ export const GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP: GcpCredentialsTypeFieldMap = { 'credentials-file': ['gcp.credentials.file'], 'credentials-json': ['gcp.credentials.json'], }; + +export const AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP: AzureCredentialsTypeFieldMap = { + manual: [], + arm_template: [], +}; diff --git a/x-pack/plugins/cloud_security_posture/common/types.ts b/x-pack/plugins/cloud_security_posture/common/types.ts index 036826ba9e6de0..092129a6762e25 100644 --- a/x-pack/plugins/cloud_security_posture/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/common/types.ts @@ -30,6 +30,12 @@ export type GcpCredentialsTypeFieldMap = { [key in GcpCredentialsType]: string[]; }; +export type AzureCredentialsType = 'arm_template' | 'manual'; + +export type AzureCredentialsTypeFieldMap = { + [key in AzureCredentialsType]: string[]; +}; + export type Evaluation = 'passed' | 'failed' | 'NA'; export type PostureTypes = 'cspm' | 'kspm' | 'vuln_mgmt' | 'all'; diff --git a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts index 1cf006589bd7a0..85815e780b062c 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts @@ -20,6 +20,7 @@ import { CSP_RULE_TEMPLATE_SAVED_OBJECT_TYPE, AWS_CREDENTIALS_TYPE_TO_FIELDS_MAP, GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP, + AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP, } from '../constants'; import type { BenchmarkId, @@ -27,6 +28,7 @@ import type { BaseCspSetupStatus, AwsCredentialsType, GcpCredentialsType, + AzureCredentialsType, RuleSection, } from '../types'; @@ -119,6 +121,8 @@ export const cleanupCredentials = (packagePolicy: NewPackagePolicy | UpdatePacka enabledInput?.streams?.[0].vars?.['aws.credentials.type']?.value; const gcpCredentialType: GcpCredentialsType | undefined = enabledInput?.streams?.[0].vars?.['gcp.credentials.type']?.value; + const azureCredentialType: AzureCredentialsType | undefined = + enabledInput?.streams?.[0].vars?.['azure.credentials.type']?.value; if (awsCredentialType || gcpCredentialType) { let credsToKeep: string[] = [' ']; @@ -129,6 +133,9 @@ export const cleanupCredentials = (packagePolicy: NewPackagePolicy | UpdatePacka } else if (gcpCredentialType) { credsToKeep = GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP[gcpCredentialType]; credFields = Object.values(GCP_CREDENTIALS_TYPE_TO_FIELDS_MAP).flat(); + } else if (azureCredentialType) { + credsToKeep = AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP[azureCredentialType]; + credFields = Object.values(AZURE_CREDENTIALS_TYPE_TO_FIELDS_MAP).flat(); } if (credsToKeep) { diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 4a5d5bfc7bd9a1..eb6318e7c67279 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -95,6 +95,7 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { icon: googleCloudLogo, isBeta: true, }, + // needs to be a function that disables/enabled based on integration version { type: CLOUDBEAT_AZURE, name: i18n.translate('xpack.csp.cspmIntegration.azureOption.nameTitle', { @@ -103,11 +104,9 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { benchmark: i18n.translate('xpack.csp.cspmIntegration.azureOption.benchmarkTitle', { defaultMessage: 'CIS Azure', }), - disabled: true, + disabled: false, + isBeta: true, icon: 'logoAzure', - tooltip: i18n.translate('xpack.csp.cspmIntegration.azureOption.tooltipContent', { - defaultMessage: 'Coming soon', - }), }, ], }, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx new file mode 100644 index 00000000000000..51ef9c7bcb955d --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx @@ -0,0 +1,238 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useEffect } from 'react'; +import { EuiLink, EuiSpacer, EuiText, EuiTitle, EuiCallOut, EuiHorizontalRule } from '@elastic/eui'; +import type { NewPackagePolicy } from '@kbn/fleet-plugin/public'; +import { NewPackagePolicyInput, PackageInfo } from '@kbn/fleet-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; +import { i18n } from '@kbn/i18n'; +import semverValid from 'semver/functions/valid'; +import semverCoerce from 'semver/functions/coerce'; +import semverLt from 'semver/functions/lt'; +import { SetupFormat, useAzureCredentialsForm } from './hooks'; +import { NewPackagePolicyPostureInput } from '../utils'; +import { CspRadioOption, RadioGroup } from '../csp_boxed_radio_group'; + +interface AzureSetupInfoContentProps { + integrationLink: string; +} + +export const AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE = 'arm_template'; +export const AZURE_MANUAL_CREDENTIAL_TYPE = 'manual'; + +const AzureSetupInfoContent = ({ integrationLink }: AzureSetupInfoContentProps) => { + return ( + <> + + +

+ +

+
+ + + + + + ), + }} + /> + + + ); +}; + +const getSetupFormatOptions = (): CspRadioOption[] => [ + { + id: AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE, + label: 'ARM Template', + }, + { + id: AZURE_MANUAL_CREDENTIAL_TYPE, + label: i18n.translate('xpack.csp.azureIntegration.setupFormatOptions.manual', { + defaultMessage: 'Manual', + }), + disabled: true, + tooltip: i18n.translate( + 'xpack.csp.azureIntegration.setupFormatOptions.manual.disabledTooltip', + { defaultMessage: 'Coming Soon' } + ), + }, +]; + +interface Props { + newPolicy: NewPackagePolicy; + input: Extract; + updatePolicy(updatedPolicy: NewPackagePolicy): void; + packageInfo: PackageInfo; + onChange: any; + setIsValid: (isValid: boolean) => void; +} + +const ARM_TEMPLATE_EXTERNAL_DOC_URL = + 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/'; + +const ArmTemplateSetup = ({ + hasArmTemplateUrl, + input, +}: { + hasArmTemplateUrl: boolean; + input: NewPackagePolicyInput; +}) => { + if (!hasArmTemplateUrl) { + return ( + + + + ); + } + + return ( + <> + +
    +
  1. + +
  2. +
  3. + +
  4. +
  5. + +
  6. +
+
+ + + + {i18n.translate('xpack.csp.azureIntegration.documentationLinkText', { + defaultMessage: 'documentation', + })} + + ), + }} + /> + + + ); +}; + +const AZURE_MINIMUM_PACKAGE_VERSION = '1.6.0'; + +export const AzureCredentialsForm = ({ + input, + newPolicy, + updatePolicy, + packageInfo, + onChange, + setIsValid, +}: Props) => { + const { setupFormat, onSetupFormatChange, integrationLink, hasArmTemplateUrl } = + useAzureCredentialsForm({ + newPolicy, + input, + packageInfo, + onChange, + setIsValid, + updatePolicy, + }); + + useEffect(() => { + if (!setupFormat) { + onSetupFormatChange(AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE); + } + }, [setupFormat, onSetupFormatChange]); + + const packageSemanticVersion = semverValid(packageInfo.version); + const cleanPackageVersion = semverCoerce(packageSemanticVersion) || ''; + const isPackageVersionValidForAzure = !semverLt( + cleanPackageVersion, + AZURE_MINIMUM_PACKAGE_VERSION + ); + + useEffect(() => { + setIsValid(isPackageVersionValidForAzure); + + onChange({ + isValid: isPackageVersionValidForAzure, + updatedPolicy: newPolicy, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [input, packageInfo, setupFormat]); + + if (!isPackageVersionValidForAzure) { + return ( + <> + + + + + + ); + } + + return ( + <> + + + + idSelected !== setupFormat && onSetupFormatChange(idSelected) + } + /> + + {setupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE && ( + + )} + + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx new file mode 100644 index 00000000000000..5a074ad4c4ebc6 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/get_azure_credentials_form_options.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { AzureCredentialsType } from '../../../../common/types'; + +export type AzureCredentialsFields = Record; + +export interface AzureOptionValue { + label: string; + info: React.ReactNode; + fields: AzureCredentialsFields; +} + +export type AzureOptions = Record; + +export const getInputVarsFields = (input: NewPackagePolicyInput, fields: AzureCredentialsFields) => + Object.entries(input.streams[0].vars || {}) + .filter(([id]) => id in fields) + .map(([id, inputVar]) => { + const field = fields[id]; + return { + id, + label: field.label, + type: field.type || 'text', + value: inputVar.value, + } as const; + }); + +export const DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE = 'manual'; + +export const getAzureCredentialsFormOptions = (): AzureOptions => ({ + arm_template: { + label: 'ARM Template', + info: [], + fields: {}, + }, + manual: { + label: i18n.translate('xpack.csp.azureIntegration.credentialType.manualLabel', { + defaultMessage: 'Manual', + }), + info: [], + fields: {}, + }, +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts new file mode 100644 index 00000000000000..011c39cf8038ee --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/hooks.ts @@ -0,0 +1,176 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useRef } from 'react'; +import { NewPackagePolicy, PackageInfo } from '@kbn/fleet-plugin/common'; +import { AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE } from './azure_credentials_form'; +import { cspIntegrationDocsNavigation } from '../../../common/navigation/constants'; +import { + getArmTemplateUrlFromCspmPackage, + getPosturePolicy, + NewPackagePolicyPostureInput, +} from '../utils'; +import { + DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE, + getAzureCredentialsFormOptions, + getInputVarsFields, +} from './get_azure_credentials_form_options'; +import { CLOUDBEAT_AZURE } from '../../../../common/constants'; +import { AzureCredentialsType } from '../../../../common/types'; + +export type SetupFormat = AzureCredentialsType; + +const getAzureCredentialsType = ( + input: Extract +): AzureCredentialsType | undefined => input.streams[0].vars?.['azure.credentials.type']?.value; + +const getAzureArmTemplateUrl = (newPolicy: NewPackagePolicy) => { + const template: string | undefined = newPolicy?.inputs?.find((i) => i.type === CLOUDBEAT_AZURE) + ?.config?.arm_template_url?.value; + + return template || undefined; +}; + +const updateAzureArmTemplateUrlInPolicy = ( + newPolicy: NewPackagePolicy, + updatePolicy: (policy: NewPackagePolicy) => void, + templateUrl: string | undefined +) => { + updatePolicy?.({ + ...newPolicy, + inputs: newPolicy.inputs.map((input) => { + if (input.type === CLOUDBEAT_AZURE) { + return { + ...input, + config: { arm_template_url: { value: templateUrl } }, + }; + } + return input; + }), + }); +}; + +const useUpdateAzureArmTemplate = ({ + packageInfo, + newPolicy, + updatePolicy, + setupFormat, +}: { + packageInfo: PackageInfo; + newPolicy: NewPackagePolicy; + updatePolicy: (policy: NewPackagePolicy) => void; + setupFormat: SetupFormat; +}) => { + useEffect(() => { + const azureArmTemplateUrl = getAzureArmTemplateUrl(newPolicy); + + if (setupFormat === 'manual') { + if (!!azureArmTemplateUrl) { + updateAzureArmTemplateUrlInPolicy(newPolicy, updatePolicy, undefined); + } + return; + } + const templateUrl = getArmTemplateUrlFromCspmPackage(packageInfo); + + if (templateUrl === '') return; + + if (azureArmTemplateUrl === templateUrl) return; + + updateAzureArmTemplateUrlInPolicy(newPolicy, updatePolicy, templateUrl); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [newPolicy?.vars?.arm_template_url, newPolicy, packageInfo, setupFormat]); +}; + +export const useAzureCredentialsForm = ({ + newPolicy, + input, + packageInfo, + onChange, + setIsValid, + updatePolicy, +}: { + newPolicy: NewPackagePolicy; + input: Extract; + packageInfo: PackageInfo; + onChange: (opts: any) => void; + setIsValid: (isValid: boolean) => void; + updatePolicy: (updatedPolicy: NewPackagePolicy) => void; +}) => { + const azureCredentialsType: AzureCredentialsType = + getAzureCredentialsType(input) || AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE; + + const options = getAzureCredentialsFormOptions(); + + const hasArmTemplateUrl = !!getArmTemplateUrlFromCspmPackage(packageInfo); + + const setupFormat = azureCredentialsType; + + const group = options[azureCredentialsType]; + const fields = getInputVarsFields(input, group.fields); + const fieldsSnapshot = useRef({}); + const lastManualCredentialsType = useRef(undefined); + + useEffect(() => { + const isInvalid = setupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE && !hasArmTemplateUrl; + setIsValid(!isInvalid); + + onChange({ + isValid: !isInvalid, + updatedPolicy: newPolicy, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [setupFormat, input.type]); + + const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; + + useUpdateAzureArmTemplate({ + packageInfo, + newPolicy, + updatePolicy, + setupFormat, + }); + + const onSetupFormatChange = (newSetupFormat: SetupFormat) => { + if (newSetupFormat === AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE) { + fieldsSnapshot.current = Object.fromEntries( + fields?.map((field) => [field.id, { value: field.value }]) + ); + + lastManualCredentialsType.current = getAzureCredentialsType(input); + + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'azure.credentials.type': { + value: AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE, + type: 'text', + }, + ...Object.fromEntries(fields?.map((field) => [field.id, { value: undefined }])), + }) + ); + } else { + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'azure.credentials.type': { + value: lastManualCredentialsType.current || DEFAULT_AZURE_MANUAL_CREDENTIALS_TYPE, + type: 'text', + }, + ...fieldsSnapshot.current, + }) + ); + } + }; + + return { + azureCredentialsType, + setupFormat, + group, + fields, + integrationLink, + hasArmTemplateUrl, + onSetupFormatChange, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx index c9ba38eccb2e62..9a50658a6a1f3b 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/csp_boxed_radio_group.tsx @@ -17,7 +17,7 @@ export interface CspRadioGroupProps { size?: 's' | 'm'; } -interface CspRadioOption { +export interface CspRadioOption { disabled?: boolean; id: string; label: string; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts index 2f2d44895db36b..c04114fc834879 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/mocks.ts @@ -19,6 +19,7 @@ import type { PostureInput } from '../../../common/types'; export const getMockPolicyAWS = () => getPolicyMock(CLOUDBEAT_AWS, 'cspm', 'aws'); export const getMockPolicyGCP = () => getPolicyMock(CLOUDBEAT_GCP, 'cspm', 'gcp'); +export const getMockPolicyAzure = () => getPolicyMock(CLOUDBEAT_AZURE, 'cspm', 'azure'); export const getMockPolicyK8s = () => getPolicyMock(CLOUDBEAT_VANILLA, 'kspm', 'self_managed'); export const getMockPolicyEKS = () => getPolicyMock(CLOUDBEAT_EKS, 'kspm', 'eks'); export const getMockPolicyVulnMgmtAWS = () => @@ -102,6 +103,28 @@ export const getMockPackageInfoCspmGCP = (packageVersion = '1.5.2') => { } as PackageInfo; }; +export const getMockPackageInfoCspmAzure = (packageVersion = '1.6.0') => { + return { + version: packageVersion, + name: 'cspm', + policy_templates: [ + { + title: '', + description: '', + name: 'cspm', + inputs: [ + { + type: CLOUDBEAT_AZURE, + title: 'Azure', + description: '', + vars: [{}], + }, + ], + }, + ], + } as PackageInfo; +}; + const getPolicyMock = ( type: PostureInput, posture: string, @@ -136,6 +159,11 @@ const getPolicyMock = ( 'gcp.credentials.type': { type: 'text' }, }; + const azureVarsMock = { + 'azure.account_type': { type: 'text' }, + 'azure.credentials.type': { type: 'text' }, + }; + const dataStream = { type: 'logs', dataset: 'cloud_security_posture.findings' }; return { @@ -182,7 +210,9 @@ const getPolicyMock = ( type: CLOUDBEAT_AZURE, policy_template: 'cspm', enabled: false, - streams: [{ enabled: false, data_stream: dataStream }], + streams: [ + { enabled: type === CLOUDBEAT_AZURE, data_stream: dataStream, vars: azureVarsMock }, + ], }, { type: CLOUDBEAT_VULN_MGMT_AWS, diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index c5d4c0e8de3e2c..5cb50fd49bc7ba 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -14,9 +14,11 @@ import { import { TestProvider } from '../../test/test_provider'; import { getMockPackageInfoCspmAWS, + getMockPackageInfoCspmAzure, getMockPackageInfoCspmGCP, getMockPackageInfoVulnMgmtAWS, getMockPolicyAWS, + getMockPolicyAzure, getMockPolicyEKS, getMockPolicyGCP, getMockPolicyK8s, @@ -30,7 +32,12 @@ import type { } from '@kbn/fleet-plugin/common'; import userEvent from '@testing-library/user-event'; import { getPosturePolicy } from './utils'; -import { CLOUDBEAT_AWS, CLOUDBEAT_EKS, CLOUDBEAT_GCP } from '../../../common/constants'; +import { + CLOUDBEAT_AWS, + CLOUDBEAT_AZURE, + CLOUDBEAT_EKS, + CLOUDBEAT_GCP, +} from '../../../common/constants'; import { useParams } from 'react-router-dom'; import { createReactQueryResponse } from '../../test/fixtures/react_query'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; @@ -205,7 +212,7 @@ describe('', () => { expect(option3).toBeInTheDocument(); expect(option1).toBeEnabled(); expect(option2).toBeEnabled(); - expect(option3).toBeDisabled(); + expect(option3).toBeEnabled(); expect(option1).toBeChecked(); }); @@ -1130,4 +1137,44 @@ describe('', () => { }); }); }); + + describe('Azure Credentials input fields', () => { + it(`renders ${CLOUDBEAT_AZURE} Not supported when version is not at least version 1.6.0`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'arm_template' }, + 'azure.account_type': { value: 'single-account-azure' }, + }); + + const { getByText } = render( + + ); + + expect(onChange).toHaveBeenCalledWith({ + isValid: false, + updatedPolicy: policy, + }); + + expect( + getByText( + 'CIS Azure is not supported on the current Integration version, please upgrade your integration to the latest version to use CIS Azure' + ) + ).toBeInTheDocument(); + }); + + it(`selects default ${CLOUDBEAT_AZURE} fields`, () => { + let policy = getMockPolicyAzure(); + policy = getPosturePolicy(policy, CLOUDBEAT_AZURE, { + 'azure.credentials.type': { value: 'arm_template' }, + 'azure.account_type': { value: 'single-account-azure' }, + }); + + render(); + + expect(onChange).toHaveBeenCalledWith({ + isValid: true, + updatedPolicy: policy, + }); + }); + }); }); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 9ee0a7ac18f76a..67a617decac761 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -27,6 +27,7 @@ import type { import { PackageInfo, PackagePolicy } from '@kbn/fleet-plugin/common'; import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import { AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE } from './azure_credentials_form/azure_credentials_form'; import { CspRadioGroupProps, RadioGroup } from './csp_boxed_radio_group'; import { assert } from '../../../common/utils/helpers'; import type { PostureInput, CloudSecurityPolicyTemplate } from '../../../common/types'; @@ -83,7 +84,11 @@ export const AWS_SINGLE_ACCOUNT = 'single-account'; export const AWS_ORGANIZATION_ACCOUNT = 'organization-account'; export const GCP_SINGLE_ACCOUNT = 'single-account-gcp'; export const GCP_ORGANIZATION_ACCOUNT = 'organization-account-gcp'; +export const AZURE_SINGLE_ACCOUNT = 'single-account-azure'; +export const AZURE_ORGANIZATION_ACCOUNT = 'organization-account-azure'; + type AwsAccountType = typeof AWS_SINGLE_ACCOUNT | typeof AWS_ORGANIZATION_ACCOUNT; +type AzureAccountType = typeof AZURE_SINGLE_ACCOUNT | typeof AZURE_ORGANIZATION_ACCOUNT; const getAwsAccountTypeOptions = (isAwsOrgDisabled: boolean): CspRadioGroupProps['options'] => [ { @@ -128,6 +133,28 @@ const getGcpAccountTypeOptions = (): CspRadioGroupProps['options'] => [ }, ]; +const getAzureAccountTypeOptions = (): CspRadioGroupProps['options'] => [ + { + id: AZURE_ORGANIZATION_ACCOUNT, + label: i18n.translate('xpack.csp.fleetIntegration.azureAccountType.azureOrganizationLabel', { + defaultMessage: 'Azure Organization', + }), + disabled: true, + tooltip: i18n.translate( + 'xpack.csp.fleetIntegration.azureAccountType.azureOrganizationDisabledTooltip', + { + defaultMessage: 'Coming Soon', + } + ), + }, + { + id: AZURE_SINGLE_ACCOUNT, + label: i18n.translate('xpack.csp.fleetIntegration.azureAccountType.singleAccountLabel', { + defaultMessage: 'Single Subscription', + }), + }, +]; + const getAwsAccountType = ( input: Extract ): AwsAccountType | undefined => input.streams[0].vars?.['aws.account_type']?.value; @@ -175,7 +202,7 @@ const AwsAccountTypeSelect = ({ @@ -277,6 +304,89 @@ const GcpAccountTypeSelect = ({ ); }; +const getAzureAccountType = ( + input: Extract +): AzureAccountType | undefined => input.streams[0].vars?.['azure.account_type']?.value; + +const AzureAccountTypeSelect = ({ + input, + newPolicy, + updatePolicy, +}: { + input: Extract; + newPolicy: NewPackagePolicy; + updatePolicy: (updatedPolicy: NewPackagePolicy) => void; +}) => { + const azureAccountTypeOptions = getAzureAccountTypeOptions(); + + useEffect(() => { + if (!getAzureAccountType(input)) { + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'azure.account_type': { + value: AZURE_SINGLE_ACCOUNT, + type: 'text', + }, + 'azure.credentials.type': { + value: AZURE_ARM_TEMPLATE_CREDENTIAL_TYPE, + type: 'text', + }, + }) + ); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [input, updatePolicy]); + + return ( + <> + + + + + { + updatePolicy( + getPosturePolicy(newPolicy, input.type, { + 'azure.account_type': { + value: accountType, + type: 'text', + }, + }) + ); + }} + size="m" + /> + {getAzureAccountType(input) === AZURE_ORGANIZATION_ACCOUNT && ( + <> + + + + + + )} + {getAzureAccountType(input) === AZURE_SINGLE_ACCOUNT && ( + <> + + + + + + )} + + ); +}; + const IntegrationSettings = ({ onChange, fields }: IntegrationInfoFieldsProps) => (
{fields.map(({ value, id, label, error }) => ( @@ -303,7 +413,9 @@ export const CspPolicyTemplateForm = memo onChange({ isValid, updatedPolicy }), + (updatedPolicy: NewPackagePolicy) => { + onChange({ isValid, updatedPolicy }); + }, [onChange, isValid] ); /** @@ -434,13 +546,6 @@ export const CspPolicyTemplateForm = memo - {/* Defines the name/description */} - updatePolicy({ ...newPolicy, [field]: value })} - /> - - {/* AWS account type selection box */} {input.type === 'cloudbeat/cis_aws' && ( )} + {input.type === 'cloudbeat/cis_azure' && ( + + )} + + {/* Defines the name/description */} + + updatePolicy({ ...newPolicy, [field]: value })} + /> + {/* Defines the vars of the enabled input of the active policy template */} ; case 'cloudbeat/cis_gcp': return ; + case 'cloudbeat/cis_azure': + return ; default: return null; } diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 7d4233b8016df6..9db4c9bf22a75d 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -100,7 +100,6 @@ const getPostureInput = ( enabled: isInputEnabled, // Merge new vars with existing vars ...(isInputEnabled && - stream.vars && inputVars && { vars: { ...stream.vars, @@ -183,6 +182,24 @@ export const getCspmCloudFormationDefaultValue = (packageInfo: PackageInfo): str return cloudFormationTemplate; }; +export const getArmTemplateUrlFromCspmPackage = (packageInfo: PackageInfo): string => { + if (!packageInfo.policy_templates) return ''; + + const policyTemplate = packageInfo.policy_templates.find((p) => p.name === CSPM_POLICY_TEMPLATE); + if (!policyTemplate) return ''; + + const policyTemplateInputs = hasPolicyTemplateInputs(policyTemplate) && policyTemplate.inputs; + if (!policyTemplateInputs) return ''; + + const armTemplateUrl = policyTemplateInputs.reduce((acc, input): string => { + if (!input.vars) return acc; + const template = input.vars.find((v) => v.name === 'arm_template_url')?.default; + return template ? String(template) : acc; + }, ''); + + return armTemplateUrl; +}; + /** * Input vars that are hidden from the user */ diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_azure_arm_template_modal.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_azure_arm_template_modal.tsx new file mode 100644 index 00000000000000..747a894a647fe0 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/post_install_azure_arm_template_modal.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiCallOut, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSpacer, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useQuery } from '@tanstack/react-query'; + +import { getAzureArmPropsFromPackagePolicy } from '../../../../../../../services/get_azure_arm_props_from_package_policy'; + +import { useCreateAzureArmTemplateUrl } from '../../../../../../../hooks/use_create_azure_arm_template_url'; + +import { AzureArmTemplateGuide } from '../../../../../../../components/azure_arm_template_guide'; + +import type { AgentPolicy, PackagePolicy } from '../../../../../types'; +import { sendGetEnrollmentAPIKeys } from '../../../../../hooks'; + +export const PostInstallAzureArmTemplateModal: React.FunctionComponent<{ + onConfirm: () => void; + onCancel: () => void; + agentPolicy: AgentPolicy; + packagePolicy: PackagePolicy; +}> = ({ onConfirm, onCancel, agentPolicy, packagePolicy }) => { + const { data: apyKeysData } = useQuery(['cloudFormationApiKeys'], () => + sendGetEnrollmentAPIKeys({ + page: 1, + perPage: 1, + kuery: `policy_id:${agentPolicy.id}`, + }) + ); + + const azureArmTemplateProps = getAzureArmPropsFromPackagePolicy(packagePolicy); + + const { azureArmTemplateUrl, error, isError, isLoading } = useCreateAzureArmTemplateUrl({ + enrollmentAPIKey: apyKeysData?.data?.items[0]?.api_key, + azureArmTemplateProps, + }); + + return ( + + + + + + + + + + {error && isError && ( + <> + + + + )} + + + + + + + { + window.open(azureArmTemplateUrl); + onConfirm(); + }} + fill + color="primary" + isLoading={isLoading} + isDisabled={isError} + > + + + + + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx index da4ecfbe3569aa..f76ef340a2c983 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx @@ -9,6 +9,8 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { safeLoad } from 'js-yaml'; +import { getAzureArmPropsFromPackagePolicy } from '../../../../../../../services/get_azure_arm_props_from_package_policy'; + import type { AgentPolicy, NewPackagePolicy, @@ -304,12 +306,21 @@ export function useOnSubmit({ force, }); + const hasAzureArmTemplate = data?.item + ? getAzureArmPropsFromPackagePolicy(data.item).templateUrl + : false; + const hasCloudFormation = data?.item ? getCloudFormationPropsFromPackagePolicy(data.item).templateUrl : false; const hasGoogleCloudShell = data?.item ? getCloudShellUrlFromPackagePolicy(data.item) : false; + if (hasAzureArmTemplate) { + setFormState(agentCount ? 'SUBMITTED' : 'SUBMITTED_AZURE_ARM_TEMPLATE'); + } else { + setFormState(agentCount ? 'SUBMITTED' : 'SUBMITTED_NO_AGENTS'); + } if (hasCloudFormation) { setFormState(agentCount ? 'SUBMITTED' : 'SUBMITTED_CLOUD_FORMATION'); } else { @@ -324,6 +335,10 @@ export function useOnSubmit({ setSavedPackagePolicy(data!.item); const hasAgentsAssigned = agentCount && agentPolicy; + if (!hasAgentsAssigned && hasAzureArmTemplate) { + setFormState('SUBMITTED_AZURE_ARM_TEMPLATE'); + return; + } if (!hasAgentsAssigned && hasCloudFormation) { setFormState('SUBMITTED_CLOUD_FORMATION'); return; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index e7a35ae48dbda6..375a19b41cdc06 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -61,6 +61,7 @@ import { CreatePackagePolicySinglePageLayout, PostInstallAddAgentModal } from '. import { useDevToolsRequest, useOnSubmit } from './hooks'; import { PostInstallCloudFormationModal } from './components/post_install_cloud_formation_modal'; import { PostInstallGoogleCloudShellModal } from './components/post_install_google_cloud_shell_modal'; +import { PostInstallAzureArmTemplateModal } from './components/post_install_azure_arm_template_modal'; const StepsWithLessPadding = styled(EuiSteps)` .euiStep__content { @@ -415,6 +416,14 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ onCancel={() => navigateAddAgentHelp(savedPackagePolicy)} /> )} + {formState === 'SUBMITTED_AZURE_ARM_TEMPLATE' && agentPolicy && savedPackagePolicy && ( + navigateAddAgent(savedPackagePolicy)} + onCancel={() => navigateAddAgentHelp(savedPackagePolicy)} + /> + )} {formState === 'SUBMITTED_CLOUD_FORMATION' && agentPolicy && savedPackagePolicy && ( = ({ + enrollmentAPIKey, + cloudSecurityIntegration, +}) => { + const { isLoading, azureArmTemplateUrl, error, isError } = useCreateAzureArmTemplateUrl({ + enrollmentAPIKey, + azureArmTemplateProps: cloudSecurityIntegration?.azureArmTemplateProps, + }); + + if (error && isError) { + return ( + <> + + + + ); + } + + return ( + + + + + + + + ); +}; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/hooks.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/hooks.tsx index 9345e4e3a66635..bc541580ddce7e 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/hooks.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/hooks.tsx @@ -7,6 +7,10 @@ import { useState, useEffect, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS } from '../../services/get_template_url_from_package_info'; + +import { SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG } from '../../services/get_template_url_from_agent_policy'; + import type { PackagePolicy, AgentPolicy } from '../../types'; import { sendGetOneAgentPolicy, useGetPackageInfoByKeyQuery, useStartServices } from '../../hooks'; import { @@ -14,18 +18,16 @@ import { FLEET_CLOUD_SECURITY_POSTURE_PACKAGE, FLEET_CLOUD_DEFEND_PACKAGE, } from '../../../common'; -import { getCloudShellUrlFromAgentPolicy } from '../../services'; +import { getTemplateUrlFromPackageInfo, getCloudShellUrlFromAgentPolicy } from '../../services'; -import { - getCloudFormationTemplateUrlFromPackageInfo, - getCloudFormationTemplateUrlFromAgentPolicy, -} from '../../services'; +import { getTemplateUrlFromAgentPolicy } from '../../services'; import type { K8sMode, CloudSecurityIntegrationType, CloudSecurityIntegrationAwsAccountType, CloudSecurityIntegration, + CloudSecurityIntegrationAzureAccountType, } from './types'; // Packages that requires custom elastic-agent manifest @@ -99,6 +101,9 @@ export function useCloudSecurityIntegration(agentPolicy?: AgentPolicy) { { enabled: Boolean(cloudSecurityPackagePolicy) } ); + const AWS_ACCOUNT_TYPE = 'aws.account_type'; + const AZURE_ACCOUNT_TYPE = 'azure.account_type'; + const cloudSecurityIntegration: CloudSecurityIntegration | undefined = useMemo(() => { if (!agentPolicy || !cloudSecurityPackagePolicy) { return undefined; @@ -109,8 +114,15 @@ export function useCloudSecurityIntegration(agentPolicy?: AgentPolicy) { if (!integrationType) return undefined; - const cloudFormationTemplateFromAgentPolicy = - getCloudFormationTemplateUrlFromAgentPolicy(agentPolicy); + const cloudFormationTemplateFromAgentPolicy = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.CLOUD_FORMATION, + agentPolicy + ); + + const azureArmTemplateFromAgentPolicy = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.ARM_TEMPLATE, + agentPolicy + ); // Use the latest CloudFormation template for the current version // So it guarantee that the template version matches the integration version @@ -118,16 +130,31 @@ export function useCloudSecurityIntegration(agentPolicy?: AgentPolicy) { // In case it can't find the template for the current version, // it will fallback to the one from the agent policy. const cloudFormationTemplateUrl = packageInfoData?.item - ? getCloudFormationTemplateUrlFromPackageInfo(packageInfoData.item, integrationType) + ? getTemplateUrlFromPackageInfo( + packageInfoData.item, + integrationType, + SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS.CLOUD_FORMATION + ) : cloudFormationTemplateFromAgentPolicy; - const AWS_ACCOUNT_TYPE = 'aws.account_type'; - const cloudFormationAwsAccountType: CloudSecurityIntegrationAwsAccountType | undefined = cloudSecurityPackagePolicy?.inputs?.find((input) => input.enabled)?.streams?.[0]?.vars?.[ AWS_ACCOUNT_TYPE ]?.value; + const azureArmTemplateUrl = packageInfoData?.item + ? getTemplateUrlFromPackageInfo( + packageInfoData.item, + integrationType, + SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS.ARM_TEMPLATE + ) + : azureArmTemplateFromAgentPolicy; + + const azureArmTemplateAccountType: CloudSecurityIntegrationAzureAccountType | undefined = + cloudSecurityPackagePolicy?.inputs?.find((input) => input.enabled)?.streams?.[0]?.vars?.[ + AZURE_ACCOUNT_TYPE + ]?.value; + const cloudShellUrl = getCloudShellUrlFromAgentPolicy(agentPolicy); return { isLoading, @@ -137,6 +164,11 @@ export function useCloudSecurityIntegration(agentPolicy?: AgentPolicy) { awsAccountType: cloudFormationAwsAccountType, templateUrl: cloudFormationTemplateUrl, }, + isAzureArmTemplate: Boolean(azureArmTemplateFromAgentPolicy), + azureArmTemplateProps: { + azureAccountType: azureArmTemplateAccountType, + templateUrl: azureArmTemplateUrl, + }, cloudShellUrl, }; }, [agentPolicy, packageInfoData?.item, isLoading, cloudSecurityPackagePolicy]); diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx index 0a413856e4f34e..39d4ab5e0428d5 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/instructions.tsx @@ -82,6 +82,7 @@ export const Instructions = (props: InstructionProps) => { useEffect(() => { // If we detect a CloudFormation integration, we want to hide the selection type if ( + props.cloudSecurityIntegration?.isAzureArmTemplate || props.cloudSecurityIntegration?.isCloudFormation || props.cloudSecurityIntegration?.cloudShellUrl ) { diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx index 12a0025efd46d0..2cf22d7a26dbbc 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/compute_steps.tsx @@ -38,6 +38,7 @@ import { InstallManagedAgentStep, InstallCloudFormationManagedAgentStep, InstallGoogleCloudShellManagedAgentStep, + InstallAzureArmTemplateManagedAgentStep, IncomingDataConfirmationStep, } from '.'; @@ -274,6 +275,15 @@ export const ManagedSteps: React.FunctionComponent = ({ cloudShellCommand: installManagedCommands.googleCloudShell, }) ); + } else if (cloudSecurityIntegration?.isAzureArmTemplate) { + steps.push( + InstallAzureArmTemplateManagedAgentStep({ + selectedApiKeyId, + apiKeyData, + enrollToken, + cloudSecurityIntegration, + }) + ); } else { steps.push( InstallManagedAgentStep({ diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/index.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/index.tsx index 8c9adb376f423f..a068cd8de6af51 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/index.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/index.tsx @@ -10,6 +10,7 @@ export * from './agent_enrollment_key_selection_step'; export * from './agent_policy_selection_step'; export * from './configure_standalone_agent_step'; export * from './incoming_data_confirmation_step'; +export * from './install_azure_arm_template_managed_agent_step'; export * from './install_cloud_formation_managed_agent_step'; export * from './install_google_cloud_shell_managed_agent_step'; export * from './install_managed_agent_step'; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_azure_arm_template_managed_agent_step.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_azure_arm_template_managed_agent_step.tsx new file mode 100644 index 00000000000000..a24e958b389161 --- /dev/null +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/steps/install_azure_arm_template_managed_agent_step.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { i18n } from '@kbn/i18n'; + +import type { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps'; + +import { AzureArmTemplateInstructions } from '../azure_arm_template_instructions'; + +import type { GetOneEnrollmentAPIKeyResponse } from '../../../../common/types/rest_spec/enrollment_api_key'; + +import type { CloudSecurityIntegration } from '../types'; + +export const InstallAzureArmTemplateManagedAgentStep = ({ + selectedApiKeyId, + apiKeyData, + enrollToken, + isComplete, + cloudSecurityIntegration, +}: { + selectedApiKeyId?: string; + apiKeyData?: GetOneEnrollmentAPIKeyResponse | null; + enrollToken?: string; + isComplete?: boolean; + cloudSecurityIntegration?: CloudSecurityIntegration | undefined; +}): EuiContainedStepProps => { + const nonCompleteStatus = selectedApiKeyId ? undefined : 'disabled'; + const status = isComplete ? 'complete' : nonCompleteStatus; + + return { + status, + title: i18n.translate( + 'xpack.fleet.agentEnrollment.azureArmTemplate.stepEnrollAndRunAgentTitle', + { defaultMessage: 'Install Elastic Agent on your cloud' } + ), + children: + selectedApiKeyId && apiKeyData && cloudSecurityIntegration ? ( + + ) : ( + + ), + }; +}; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts index e292182a3cd92a..abad38a0d74ae3 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/types.ts @@ -17,6 +17,9 @@ export type K8sMode = export type CloudSecurityIntegrationType = 'kspm' | 'vuln_mgmt' | 'cspm'; export type CloudSecurityIntegrationAwsAccountType = 'single-account' | 'organization-account'; +export type CloudSecurityIntegrationAzureAccountType = + | 'single-account-azure' + | 'organization-account-azure'; export type FlyoutMode = 'managed' | 'standalone'; export type SelectionType = 'tabs' | 'radio' | undefined; @@ -26,11 +29,18 @@ export interface CloudFormationProps { awsAccountType: CloudSecurityIntegrationAwsAccountType | undefined; } +export interface AzureArmTemplateProps { + templateUrl: string | undefined; + azureAccountType: CloudSecurityIntegrationAzureAccountType | undefined; +} + export interface CloudSecurityIntegration { integrationType: CloudSecurityIntegrationType | undefined; isLoading: boolean; isCloudFormation: boolean; + isAzureArmTemplate: boolean; cloudFormationProps?: CloudFormationProps; + azureArmTemplateProps?: AzureArmTemplateProps; cloudShellUrl: string | undefined; } diff --git a/x-pack/plugins/fleet/public/components/azure_arm_template_guide.tsx b/x-pack/plugins/fleet/public/components/azure_arm_template_guide.tsx new file mode 100644 index 00000000000000..7cfb6542a02fef --- /dev/null +++ b/x-pack/plugins/fleet/public/components/azure_arm_template_guide.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { EuiLink, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { CloudSecurityIntegrationAzureAccountType } from './agent_enrollment_flyout/types'; + +const azureResourceManagerLink = + 'https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager'; + +export const AzureArmTemplateGuide = ({ + azureAccountType, +}: { + azureAccountType?: CloudSecurityIntegrationAzureAccountType; +}) => { + return ( + +

+ + + + ), + }} + /> +

+ +
    + {azureAccountType === 'organization-account-azure' ? ( +
  1. + +
  2. + ) : ( +
  3. + +
  4. + )} +
  5. + +
  6. +
+
+
+ ); +}; diff --git a/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts b/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts new file mode 100644 index 00000000000000..aed03272c470e4 --- /dev/null +++ b/x-pack/plugins/fleet/public/hooks/use_create_azure_arm_template_url.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +import type { AzureArmTemplateProps } from '../components/agent_enrollment_flyout/types'; + +import { useGetSettings } from './use_request'; + +export const useCreateAzureArmTemplateUrl = ({ + enrollmentAPIKey, + azureArmTemplateProps, +}: { + enrollmentAPIKey: string | undefined; + azureArmTemplateProps: AzureArmTemplateProps | undefined; +}) => { + const { data, isLoading } = useGetSettings(); + + let isError = false; + let error: string | undefined; + + // Default fleet server host + const fleetServerHost = data?.item.fleet_server_hosts?.[0]; + + if (!fleetServerHost && !isLoading) { + isError = true; + error = i18n.translate('xpack.fleet.agentEnrollment.cloudFormation.noFleetServerHost', { + defaultMessage: 'No Fleet Server host found', + }); + } + + if (!enrollmentAPIKey && !isLoading) { + isError = true; + error = i18n.translate('xpack.fleet.agentEnrollment.cloudFormation.noApiKey', { + defaultMessage: 'No enrollment token found', + }); + } + + const azureArmTemplateUrl = azureArmTemplateProps?.templateUrl; + + return { + isLoading, + azureArmTemplateUrl, + isError, + error, + }; +}; diff --git a/x-pack/plugins/fleet/public/services/get_azure_arm_props_from_package_policy.ts b/x-pack/plugins/fleet/public/services/get_azure_arm_props_from_package_policy.ts new file mode 100644 index 00000000000000..f064db2e6fadf6 --- /dev/null +++ b/x-pack/plugins/fleet/public/services/get_azure_arm_props_from_package_policy.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CloudSecurityIntegrationAzureAccountType } from '../components/agent_enrollment_flyout/types'; +import type { PackagePolicy } from '../types'; +import type { AzureArmTemplateProps } from '../components/agent_enrollment_flyout/types'; + +const AZURE_ACCOUNT_TYPE = 'azure.account_type'; + +/** + * Get the Azure Arm Template url from a package policy + * It looks for a config with an arm_template_url object present in the enabled inputs of the package policy + */ +export const getAzureArmPropsFromPackagePolicy = ( + packagePolicy?: PackagePolicy +): AzureArmTemplateProps => { + const templateUrl: CloudSecurityIntegrationAzureAccountType | undefined = + packagePolicy?.inputs?.find((input) => input.enabled)?.config?.arm_template_url?.value; + + const azureAccountType: CloudSecurityIntegrationAzureAccountType | undefined = + packagePolicy?.inputs?.find((input) => input.enabled)?.streams?.[0]?.vars?.[AZURE_ACCOUNT_TYPE] + ?.value; + + return { + templateUrl, + azureAccountType, + }; +}; diff --git a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.test.ts b/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.test.ts deleted file mode 100644 index 8ed2fb3ae389aa..00000000000000 --- a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.test.ts +++ /dev/null @@ -1,66 +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 { getCloudFormationTemplateUrlFromPackageInfo } from './get_cloud_formation_template_url_from_package_info'; - -describe('getCloudFormationTemplateUrlFromPackageInfo', () => { - test('returns undefined when packageInfo is undefined', () => { - const result = getCloudFormationTemplateUrlFromPackageInfo(undefined, 'test'); - expect(result).toBeUndefined(); - }); - - test('returns undefined when packageInfo has no policy_templates', () => { - const packageInfo = { inputs: [] }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromPackageInfo(packageInfo, 'test'); - expect(result).toBeUndefined(); - }); - - test('returns undefined when integrationType is not found in policy_templates', () => { - const packageInfo = { policy_templates: [{ name: 'template1' }, { name: 'template2' }] }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromPackageInfo(packageInfo, 'nonExistentTemplate'); - expect(result).toBeUndefined(); - }); - - test('returns undefined when no input in the policy template has a cloudFormationTemplate', () => { - const packageInfo = { - policy_templates: [ - { - name: 'template1', - inputs: [ - { name: 'input1', vars: [] }, - { name: 'input2', vars: [{ name: 'var1', default: 'value1' }] }, - ], - }, - ], - }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromPackageInfo(packageInfo, 'template1'); - expect(result).toBeUndefined(); - }); - - test('returns the cloudFormationTemplate from the policy template', () => { - const packageInfo = { - policy_templates: [ - { - name: 'template1', - inputs: [ - { name: 'input1', vars: [] }, - { - name: 'input2', - vars: [{ name: 'cloud_formation_template', default: 'cloud_formation_template_url' }], - }, - ], - }, - ], - }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromPackageInfo(packageInfo, 'template1'); - expect(result).toBe('cloud_formation_template_url'); - }); -}); diff --git a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.test.ts b/x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.test.ts similarity index 51% rename from x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.test.ts rename to x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.test.ts index 6b4214044f2a0c..279f64f412d903 100644 --- a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.test.ts +++ b/x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.test.ts @@ -4,18 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { getCloudFormationTemplateUrlFromAgentPolicy } from './get_cloud_formation_template_url_from_agent_policy'; +import { + getTemplateUrlFromAgentPolicy, + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG, +} from './get_template_url_from_agent_policy'; -describe('getCloudFormationTemplateUrlFromAgentPolicy', () => { +describe('getTemplateUrlFromAgentPolicy', () => { it('should return undefined when selectedPolicy is undefined', () => { - const result = getCloudFormationTemplateUrlFromAgentPolicy(); + const result = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.CLOUD_FORMATION + ); expect(result).toBeUndefined(); }); it('should return undefined when selectedPolicy has no package_policies', () => { const selectedPolicy = {}; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromAgentPolicy(selectedPolicy); + const result = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.CLOUD_FORMATION, + // @ts-expect-error + selectedPolicy + ); expect(result).toBeUndefined(); }); @@ -37,8 +45,11 @@ describe('getCloudFormationTemplateUrlFromAgentPolicy', () => { }, ], }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromAgentPolicy(selectedPolicy); + const result = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.CLOUD_FORMATION, + // @ts-expect-error + selectedPolicy + ); expect(result).toBeUndefined(); }); @@ -61,8 +72,38 @@ describe('getCloudFormationTemplateUrlFromAgentPolicy', () => { }, ], }; - // @ts-expect-error - const result = getCloudFormationTemplateUrlFromAgentPolicy(selectedPolicy); + const result = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.CLOUD_FORMATION, + // @ts-expect-error + selectedPolicy + ); + expect(result).toBe('url3'); + }); + + it('should return the first config.arm_template_url when available', () => { + const selectedPolicy = { + package_policies: [ + { + inputs: [ + { enabled: false, config: { arm_template_url: { value: 'url1' } } }, + { enabled: false, config: { arm_template_url: { value: 'url2' } } }, + { enabled: false, config: { other_property: 'value' } }, + ], + }, + { + inputs: [ + { enabled: false, config: {} }, + { enabled: true, config: { arm_template_url: { value: 'url3' } } }, + { enabled: true, config: { arm_template_url: { value: 'url4' } } }, + ], + }, + ], + }; + const result = getTemplateUrlFromAgentPolicy( + SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG.ARM_TEMPLATE, + // @ts-expect-error + selectedPolicy + ); expect(result).toBe('url3'); }); }); diff --git a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.ts b/x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.ts similarity index 66% rename from x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.ts rename to x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.ts index 81aaf5b3fd9708..203d267ecc6fa0 100644 --- a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_agent_policy.ts +++ b/x-pack/plugins/fleet/public/services/get_template_url_from_agent_policy.ts @@ -7,12 +7,15 @@ import type { AgentPolicy } from '../types'; -/** - * Get the cloud formation template url from a agent policy - * It looks for a config with a cloud_formation_template_url object present in - * the enabled package_policies inputs of the agent policy - */ -export const getCloudFormationTemplateUrlFromAgentPolicy = (selectedPolicy?: AgentPolicy) => { +export const SUPPORTED_TEMPLATES_URL_FROM_AGENT_POLICY_CONFIG = { + CLOUD_FORMATION: 'cloud_formation_template_url', + ARM_TEMPLATE: 'arm_template_url', +}; + +export const getTemplateUrlFromAgentPolicy = ( + templateUrlFieldName: string, + selectedPolicy?: AgentPolicy +) => { const cloudFormationTemplateUrl = selectedPolicy?.package_policies?.reduce( (acc, packagePolicy) => { const findCloudFormationTemplateUrlConfig = packagePolicy.inputs?.reduce( @@ -20,8 +23,8 @@ export const getCloudFormationTemplateUrlFromAgentPolicy = (selectedPolicy?: Age if (accInput !== '') { return accInput; } - if (input?.enabled && input?.config?.cloud_formation_template_url) { - return input.config.cloud_formation_template_url.value; + if (input?.enabled && input?.config?.[templateUrlFieldName]) { + return input.config[templateUrlFieldName].value; } return accInput; }, diff --git a/x-pack/plugins/fleet/public/services/get_template_url_from_package_info.test.ts b/x-pack/plugins/fleet/public/services/get_template_url_from_package_info.test.ts new file mode 100644 index 00000000000000..f2cb8e6987ea76 --- /dev/null +++ b/x-pack/plugins/fleet/public/services/get_template_url_from_package_info.test.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PackageInfo } from '../types'; + +import { + getTemplateUrlFromPackageInfo, + SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS, +} from './get_template_url_from_package_info'; + +describe('getTemplateUrlFromPackageInfo', () => { + test('returns undefined when packageInfo is undefined', () => { + const result = getTemplateUrlFromPackageInfo(undefined, 'test', 'cloud_formation_template_url'); + expect(result).toBeUndefined(); + }); + + test('returns undefined when packageInfo has no policy_templates', () => { + const packageInfo = { inputs: [] } as unknown as PackageInfo; + const result = getTemplateUrlFromPackageInfo( + packageInfo, + 'test', + 'cloud_formation_template_url' + ); + expect(result).toBeUndefined(); + }); + + test('returns undefined when integrationType is not found in policy_templates', () => { + const packageInfo = { + policy_templates: [{ name: 'template1' }, { name: 'template2' }], + } as PackageInfo; + const result = getTemplateUrlFromPackageInfo( + packageInfo, + 'nonExistentTemplate', + 'cloud_formation_template_url' + ); + expect(result).toBeUndefined(); + }); + + test('returns undefined when no input in the policy template has a cloudFormationTemplate', () => { + const packageInfo = { + policy_templates: [ + { + name: 'template1', + inputs: [ + { name: 'input1', vars: [] }, + { name: 'input2', vars: [{ name: 'var1', default: 'value1' }] }, + ], + }, + ], + } as unknown as PackageInfo; + + const result = getTemplateUrlFromPackageInfo( + packageInfo, + 'template1', + 'cloud_formation_template_url' + ); + expect(result).toBeUndefined(); + }); + + test('returns the cloudFormationTemplate from the policy template', () => { + const packageInfo = { + policy_templates: [ + { + name: 'template1', + inputs: [ + { name: 'input1', vars: [] }, + { + name: 'input2', + vars: [ + { + name: SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS.CLOUD_FORMATION, + default: 'cloud_formation_template_url', + }, + ], + }, + ], + }, + ], + } as unknown as PackageInfo; + + const result = getTemplateUrlFromPackageInfo( + packageInfo, + 'template1', + SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS.CLOUD_FORMATION + ); + expect(result).toBe('cloud_formation_template_url'); + }); + + test('returns the armTemplateUrl from the policy template', () => { + const packageInfo = { + policy_templates: [ + { + name: 'template1', + inputs: [ + { name: 'input1', vars: [] }, + { + name: 'input2', + vars: [{ name: 'arm_template_url', default: 'arm_template_url_value' }], + }, + ], + }, + ], + } as unknown as PackageInfo; + + const result = getTemplateUrlFromPackageInfo(packageInfo, 'template1', 'arm_template_url'); + expect(result).toBe('arm_template_url_value'); + }); +}); diff --git a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.ts b/x-pack/plugins/fleet/public/services/get_template_url_from_package_info.ts similarity index 68% rename from x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.ts rename to x-pack/plugins/fleet/public/services/get_template_url_from_package_info.ts index 4f5381ccedb3f5..cfb7b747d0427a 100644 --- a/x-pack/plugins/fleet/public/services/get_cloud_formation_template_url_from_package_info.ts +++ b/x-pack/plugins/fleet/public/services/get_template_url_from_package_info.ts @@ -7,14 +7,15 @@ import type { PackageInfo } from '../types'; -/** - * Get the cloud formation template url from the PackageInfo - * It looks for a input var with a object containing cloud_formation_template_url present in - * the package_policies inputs of the given integration type - */ -export const getCloudFormationTemplateUrlFromPackageInfo = ( +export const SUPPORTED_TEMPLATES_URL_FROM_PACKAGE_INFO_INPUT_VARS = { + CLOUD_FORMATION: 'cloud_formation_template', + ARM_TEMPLATE: 'arm_template_url', +}; + +export const getTemplateUrlFromPackageInfo = ( packageInfo: PackageInfo | undefined, - integrationType: string + integrationType: string, + templateUrlFieldName: string ): string | undefined => { if (!packageInfo?.policy_templates) return undefined; @@ -24,7 +25,7 @@ export const getCloudFormationTemplateUrlFromPackageInfo = ( if ('inputs' in policyTemplate) { const cloudFormationTemplate = policyTemplate.inputs?.reduce((acc, input): string => { if (!input.vars) return acc; - const template = input.vars.find((v) => v.name === 'cloud_formation_template')?.default; + const template = input.vars.find((v) => v.name === templateUrlFieldName)?.default; return template ? String(template) : acc; }, ''); return cloudFormationTemplate !== '' ? cloudFormationTemplate : undefined; diff --git a/x-pack/plugins/fleet/public/services/index.ts b/x-pack/plugins/fleet/public/services/index.ts index a98d4126d52f3e..64009e4a11061d 100644 --- a/x-pack/plugins/fleet/public/services/index.ts +++ b/x-pack/plugins/fleet/public/services/index.ts @@ -49,7 +49,7 @@ export { pkgKeyFromPackageInfo } from './pkg_key_from_package_info'; export { createExtensionRegistrationCallback } from './ui_extensions'; export { incrementPolicyName } from './increment_policy_name'; export { getCloudFormationPropsFromPackagePolicy } from './get_cloud_formation_props_from_package_policy'; -export { getCloudFormationTemplateUrlFromAgentPolicy } from './get_cloud_formation_template_url_from_agent_policy'; -export { getCloudFormationTemplateUrlFromPackageInfo } from './get_cloud_formation_template_url_from_package_info'; +export { getTemplateUrlFromAgentPolicy } from './get_template_url_from_agent_policy'; +export { getTemplateUrlFromPackageInfo } from './get_template_url_from_package_info'; export { getCloudShellUrlFromPackagePolicy } from './get_cloud_shell_url_from_package_policy'; export { getCloudShellUrlFromAgentPolicy } from './get_cloud_shell_url_from_agent_policy'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0818edbb72eee5..aa95ebb6e2aef1 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -11359,7 +11359,6 @@ "xpack.csp.cspmIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.cspmIntegration.azureOption.benchmarkTitle": "CIS Azure", "xpack.csp.cspmIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.cspmIntegration.azureOption.tooltipContent": "Bientôt disponible", "xpack.csp.cspmIntegration.gcpOption.benchmarkTitle": "CIS GCP", "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "Gestion du niveau de sécurité du cloud", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 18016ac4caa29d..0c085d75d79023 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11374,7 +11374,6 @@ "xpack.csp.cspmIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.cspmIntegration.azureOption.benchmarkTitle": "CIS Azure", "xpack.csp.cspmIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.cspmIntegration.azureOption.tooltipContent": "まもなくリリース", "xpack.csp.cspmIntegration.gcpOption.benchmarkTitle": "CIS GCP", "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "クラウドセキュリティ態勢管理", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 178fa11a295833..4cc2eb901cbbd4 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -11374,7 +11374,6 @@ "xpack.csp.cspmIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.cspmIntegration.azureOption.benchmarkTitle": "CIS Azure", "xpack.csp.cspmIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.cspmIntegration.azureOption.tooltipContent": "即将推出", "xpack.csp.cspmIntegration.gcpOption.benchmarkTitle": "CIS GCP", "xpack.csp.cspmIntegration.gcpOption.nameTitle": "GCP", "xpack.csp.cspmIntegration.integration.nameTitle": "云安全态势管理", From fb13b2181db275f8145bf13f31fb7846d7a3e80b Mon Sep 17 00:00:00 2001 From: Mashhur <99575341+mashhurs@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:44:32 -0700 Subject: [PATCH 04/22] Migrate deprecated components in Logstash pipelines section. (#161512) ## Summary Migrates the deprecated components in Logstash pipelines view based on [the gude](https://elastic.github.io/eui/#/layout/page-components). A list of deprecated components in Logstash pipelines can be found [here](https://github.com/search?q=repo%3Aelastic%2Fkibana+%2FEuiPage%5Ba-zA-Z%5D%2B_Deprecated%2F+path%3A%2F%5Ex-pack%5C%2Fplugins%5C%2Flogstash%2F&type=code). ### Tests Opened a dev tools and proceeded manual tests on local dev env (based on [local env setup guide](https://docs.elastic.dev/kibana-dev-docs/getting-started/setup-dev-env)): - create pipeline(s) - check list of pipeline(s) - delete pipeline(s) - check alerts when deleting the pipeline - check Elasticsearch .logstash_pipelines index (`GET _logstash/pipeline`) to check the data shape which Logstash polls and uses. - Closes: #161417 ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) ~~- [ ] [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 ~~- [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/))~~ - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) ~~- [ ] 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)~~ - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### Risk Matrix Delete this section if it is not applicable to this PR. Before closing this PR, invite QA, stakeholders, and other developers to identify risks that should be tested prior to the change/feature release. When forming the risk matrix, consider some of the following examples and how they may potentially impact the change: | Risk | Probability | Severity | Mitigation/Notes | |---------------------------|-------------|----------|-------------------------| | Multiple Spaces—unexpected behavior in non-default Kibana Space. | Low | High | Integration tests will verify that all features are still supported in non-default Kibana Space and when user switches between spaces. | | Multiple nodes—Elasticsearch polling might have race conditions when multiple Kibana nodes are polling for the same tasks. | High | Low | Tasks are idempotent, so executing them multiple times will not result in logical error, but will degrade performance. To test for this case we add plenty of unit tests around this logic and document manual testing procedure. | | Code should gracefully handle cases when feature X or plugin Y are disabled. | Medium | High | Unit tests will verify that any feature flag or plugin combination still results in our service operational. | | [See more potential risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) | ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../pipeline_editor.test.js.snap | 24 +++++++++---------- .../pipeline_editor/pipeline_editor.js | 6 ++--- .../components/pipeline_list/pipeline_list.js | 6 ++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap index 2bca876b670829..f635f810d1cae9 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/__snapshots__/pipeline_editor.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`PipelineEditor component includes required error message for falsy pipeline id 1`] = ` - - + `; exports[`PipelineEditor component invalidates form for invalid pipeline id input 1`] = ` - - + `; exports[`PipelineEditor component invalidates form for pipeline id with spaces 1`] = ` - - + `; exports[`PipelineEditor component matches snapshot for clone pipeline 1`] = ` - - + `; exports[`PipelineEditor component matches snapshot for create pipeline 1`] = ` - - + `; exports[`PipelineEditor component matches snapshot for edit pipeline 1`] = ` - - + `; diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js index 0f0cf333b6ebd9..a47672fd8a2292 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_editor/pipeline_editor.js @@ -22,7 +22,7 @@ import { EuiFieldText, EuiForm, EuiFormRow, - EuiPageContentBody_Deprecated as EuiPageContentBody, + EuiPageSection, EuiSelect, EuiSpacer, EuiPageHeader, @@ -266,7 +266,7 @@ class PipelineEditorUi extends React.Component { const { intl } = this.props; return ( - )} - + ); } } diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js index 0729ad5ce8b576..b80c0522f9aa15 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipeline_list.js @@ -12,7 +12,7 @@ import { EuiCallOut, EuiEmptyPrompt, EuiLoadingSpinner, - EuiPageContentBody_Deprecated as EuiPageContentBody, + EuiPageSection, EuiPageHeader, EuiSpacer, } from '@elastic/eui'; @@ -291,7 +291,7 @@ class PipelineListUi extends React.Component { const { clonePipeline, createPipeline, isReadOnly, openPipeline } = this.props; const { isSelectable, message, pipelines, selection, showConfirmDeleteModal } = this.state; return ( - + @@ -329,7 +329,7 @@ class PipelineListUi extends React.Component { showAddRoleAlert={this.state.showAddRoleAlert} showEnableMonitoringAlert={this.state.showEnableMonitoringAlert} /> - + ); } } From f9c26208b7a38152a215a7934677f0bdc68d0608 Mon Sep 17 00:00:00 2001 From: Brad White Date: Wed, 27 Sep 2023 14:14:01 -0600 Subject: [PATCH 05/22] Fix some type issues in x-pack/test (#167343) ## Summary We're breaking #166813 up into smaller PRs in the interest of getting PRs through sooner for type fixes. These are the changes for `x-pack/test`. --------- Co-authored-by: Thomas Watson Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alex Szabo --- .../create_with_circuit_breaker.ts | 4 ++-- .../tests/alerting/suggestions_value_alert.ts | 1 - .../management/ingest_pipelines/lib/fixtures.ts | 4 ++-- .../apis/security_solution/authentications.ts | 2 +- .../apm_api_integration/common/bettertest.ts | 4 ++-- .../test/apm_api_integration/common/registry.ts | 2 +- .../tests/diagnostics/indices.spec.ts | 16 ++++++++-------- .../pages/findings.ts | 4 ++++ .../exception_operators_data_types/ip_array.ts | 8 ++++---- .../exception_operators_data_types/text_array.ts | 8 ++++---- x-pack/test/disable_ems/tests/fonts.ts | 1 + .../apis/download_sources/crud.ts | 2 +- .../apis/fleet_telemetry.ts | 6 +++++- .../drilldowns/explore_data_chart_action.ts | 6 +++--- .../index_pattern/continuous_transform.ts | 1 + .../page_objects/tag_management_page.ts | 1 - x-pack/test/functional/services/ml/api.ts | 5 ++--- 17 files changed, 41 insertions(+), 34 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/schedule_circuit_breaker/create_with_circuit_breaker.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/schedule_circuit_breaker/create_with_circuit_breaker.ts index 8183f6b48f4edb..bf1a0792a0091f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/schedule_circuit_breaker/create_with_circuit_breaker.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/schedule_circuit_breaker/create_with_circuit_breaker.ts @@ -26,7 +26,7 @@ export default function createWithCircuitBreakerTests({ getService }: FtrProvide .expect(200); objectRemover.add('space1', createdRule.id, 'rule', 'alerting'); - const { body } = await supertest + await supertest .post(`${getUrlPrefix('space1')}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestRuleData({ schedule: { interval: '10s' } })) @@ -41,7 +41,7 @@ export default function createWithCircuitBreakerTests({ getService }: FtrProvide .expect(200); objectRemover.add('space1', createdRule.id, 'rule', 'alerting'); - const { body } = await supertest + await supertest .post(`${getUrlPrefix('space2')}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send(getTestRuleData({ schedule: { interval: '10s' } })) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/suggestions_value_alert.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/suggestions_value_alert.ts index 3980c174528ed8..1478a02454bb06 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/suggestions_value_alert.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/suggestions_value_alert.ts @@ -17,7 +17,6 @@ export default function createRuleSuggestionValuesTests({ getService }: FtrProvi describe('alerts/suggestions/values', async () => { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/fixtures.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/fixtures.ts index c148101749085b..344b6fab0f07f9 100644 --- a/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/fixtures.ts +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/fixtures.ts @@ -12,7 +12,7 @@ import { IngestPutPipelineRequest, } from '@elastic/elasticsearch/lib/api/types'; -interface Pipeline { +export interface Pipeline { name: string; description?: string; onFailureProcessors?: IngestProcessorContainer[]; @@ -21,7 +21,7 @@ interface Pipeline { metadata?: Metadata; } -interface IngestPutPipelineInternalRequest extends Omit { +export interface IngestPutPipelineInternalRequest extends Omit { name: string; } diff --git a/x-pack/test/api_integration/apis/security_solution/authentications.ts b/x-pack/test/api_integration/apis/security_solution/authentications.ts index aa54114e04d72d..b65c93995156b8 100644 --- a/x-pack/test/api_integration/apis/security_solution/authentications.ts +++ b/x-pack/test/api_integration/apis/security_solution/authentications.ts @@ -9,10 +9,10 @@ import expect from '@kbn/expect'; import { AuthStackByField, Direction, - UserAuthenticationsRequestOptions, UserAuthenticationsStrategyResponse, UsersQueries, } from '@kbn/security-solution-plugin/common/search_strategy'; +import type { UserAuthenticationsRequestOptions } from '@kbn/security-solution-plugin/common/api/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; diff --git a/x-pack/test/apm_api_integration/common/bettertest.ts b/x-pack/test/apm_api_integration/common/bettertest.ts index 83f7da5725db84..e1132be3f9a771 100644 --- a/x-pack/test/apm_api_integration/common/bettertest.ts +++ b/x-pack/test/apm_api_integration/common/bettertest.ts @@ -20,7 +20,7 @@ interface BetterTestOptions { body?: any; } -interface BetterTestResponse { +export interface BetterTestResponse { status: number; body: T; } @@ -72,7 +72,7 @@ export class BetterTestError extends Error { const req = res.req as any; super( `Unhandled BetterTestError: -Status: "${res.status}" +Status: "${res.status}" Path: "${req.method} ${req.path}" Body: ${JSON.stringify(res.body)}` ); diff --git a/x-pack/test/apm_api_integration/common/registry.ts b/x-pack/test/apm_api_integration/common/registry.ts index 6876854b5991dc..6ae932f59e2a47 100644 --- a/x-pack/test/apm_api_integration/common/registry.ts +++ b/x-pack/test/apm_api_integration/common/registry.ts @@ -153,7 +153,7 @@ export function RegistryProvider({ getService }: FtrProviderContext) { await supertest .get('/api/ml/saved_objects/sync') .set('kbn-xsrf', 'foo') - .auth(ApmUsername.editorUser, kbnTestConfig.getUrlParts().password); + .auth(ApmUsername.editorUser, kbnTestConfig.getUrlParts().password!); } if (condition.archives.length) { log('Loaded all archives'); diff --git a/x-pack/test/apm_api_integration/tests/diagnostics/indices.spec.ts b/x-pack/test/apm_api_integration/tests/diagnostics/indices.spec.ts index 3314b4fdcfcfc8..7822acfe923ff7 100644 --- a/x-pack/test/apm_api_integration/tests/diagnostics/indices.spec.ts +++ b/x-pack/test/apm_api_integration/tests/diagnostics/indices.spec.ts @@ -61,7 +61,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); expect(status).to.be(200); - expect(body.validIndices.length).to.be.greaterThan(0); + expect(body.validIndices?.length).to.be.greaterThan(0); expect(body.invalidIndices).to.eql([]); }); }); @@ -102,7 +102,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); expect(status).to.be(200); - expect(body.validIndices.length).to.be.greaterThan(0); + expect(body.validIndices?.length).to.be.greaterThan(0); expect(body.invalidIndices).to.eql([ { isValid: false, @@ -158,10 +158,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); expect(status).to.be(200); - expect(body.validIndices.length).to.be.greaterThan(0); - expect(body.invalidIndices.length).to.be(1); + expect(body.validIndices?.length).to.be.greaterThan(0); + expect(body.invalidIndices?.length).to.be(1); - expect(omit(body.invalidIndices[0], 'index')).to.eql({ + expect(omit(body.invalidIndices?.[0], 'index')).to.eql({ isValid: false, fieldMappings: { isValid: true }, ingestPipeline: { isValid: false }, @@ -187,9 +187,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); expect(status).to.be(200); - expect(body.validIndices.length).to.be.greaterThan(0); - expect(body.invalidIndices.length).to.be(1); - expect(omit(body.invalidIndices[0], 'index')).to.eql({ + expect(body.validIndices?.length).to.be.greaterThan(0); + expect(body.invalidIndices?.length).to.be(1); + expect(omit(body.invalidIndices?.[0], 'index')).to.eql({ isValid: false, fieldMappings: { isValid: true }, ingestPipeline: { isValid: false, id: 'logs-default-pipeline' }, diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings.ts b/x-pack/test/cloud_security_posture_functional/pages/findings.ts index 5f85b38d39dd69..5caedd4a6e7f28 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings.ts @@ -22,6 +22,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // We intentionally make some fields start with a capital letter to test that the query bar is case-insensitive/case-sensitive const data = [ { + '@timestamp': '1695819664234', resource: { id: chance.guid(), name: `kubelet`, sub_type: 'lower case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -38,6 +39,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Upper case cluster id', }, { + '@timestamp': '1695819673242', resource: { id: chance.guid(), name: `Pod`, sub_type: 'Upper case sub type' }, result: { evaluation: chance.integer() % 2 === 0 ? 'passed' : 'failed' }, rule: { @@ -54,6 +56,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'Another Upper case cluster id', }, { + '@timestamp': '1695819676242', resource: { id: chance.guid(), name: `process`, sub_type: 'another lower case type' }, result: { evaluation: 'passed' }, rule: { @@ -70,6 +73,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { cluster_id: 'lower case cluster id', }, { + '@timestamp': '1695819680202', resource: { id: chance.guid(), name: `process`, sub_type: 'Upper case type again' }, result: { evaluation: 'failed' }, rule: { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/ip_array.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/ip_array.ts index d828b332d215ad..0fcdf1a03b14bd 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/ip_array.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/ip_array.ts @@ -152,7 +152,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const ips = signalsOpen.hits.hits.map((hit) => hit._source?.ip).sort(); - expect(ips.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(ips.flat(10)).to.eql([]); }); it('should filter a CIDR range of "127.0.0.1/30"', async () => { @@ -347,7 +347,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const ips = signalsOpen.hits.hits.map((hit) => hit._source?.ip).sort(); - expect(ips.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(ips.flat(10)).to.eql([]); }); }); @@ -409,7 +409,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const ips = signalsOpen.hits.hits.map((hit) => hit._source?.ip).sort(); - expect(ips.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(ips.flat(10)).to.eql([]); }); }); @@ -514,7 +514,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const ips = signalsOpen.hits.hits.map((hit) => hit._source?.ip).sort(); - expect(ips.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(ips.flat(10)).to.eql([]); }); it('will return 2 results if we have a list which contains the CIDR ranges of "127.0.0.1/32, 127.0.0.2/31, 127.0.0.4/30"', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/text_array.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/text_array.ts index 27d28c3630293d..fe4a13fcc3c846 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/text_array.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group9/exception_operators_data_types/text_array.ts @@ -152,7 +152,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); - expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(hits.flat(10)).to.eql([]); }); }); @@ -280,7 +280,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); - expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(hits.flat(10)).to.eql([]); }); }); @@ -342,7 +342,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); - expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(hits.flat(10)).to.eql([]); }); }); @@ -522,7 +522,7 @@ export default ({ getService }: FtrProviderContext) => { await waitForSignalsToBePresent(supertest, log, 1, [id]); const signalsOpen = await getSignalsById(supertest, log, id); const hits = signalsOpen.hits.hits.map((hit) => hit._source?.text).sort(); - expect(hits.flat(Number.MAX_SAFE_INTEGER)).to.eql([]); + expect(hits.flat(10)).to.eql([]); }); }); diff --git a/x-pack/test/disable_ems/tests/fonts.ts b/x-pack/test/disable_ems/tests/fonts.ts index aec0b0a6d6802e..b8b6d6903db5e6 100644 --- a/x-pack/test/disable_ems/tests/fonts.ts +++ b/x-pack/test/disable_ems/tests/fonts.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['maps']); diff --git a/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts b/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts index 587a4b7fc884c8..8b0e5ca8c4e774 100644 --- a/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts @@ -357,7 +357,7 @@ export default function (providerContext: FtrProviderContext) { 'https://some.source.proxy:3232' ); - const res = await supertest + await supertest .put(`/api/fleet/agent_download_sources/${downloadSourceId}`) .set('kbn-xsrf', 'xxxx') .send({ diff --git a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts index e0c6799b5a3cd2..3f5c414f46ef87 100644 --- a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts +++ b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts @@ -126,7 +126,11 @@ export default function (providerContext: FtrProviderContext) { ); }); - async function waitForAgents(expectedAgentCount: number, attempts: number, _attemptsMade = 0) { + async function waitForAgents( + expectedAgentCount: number, + attempts: number, + _attemptsMade = 0 + ): Promise { const { body: apiResponse } = await supertest .get(`/api/fleet/agents?showInactive=true`) .set('kbn-xsrf', 'xxxx') diff --git a/x-pack/test/functional/apps/dashboard/group3/drilldowns/explore_data_chart_action.ts b/x-pack/test/functional/apps/dashboard/group3/drilldowns/explore_data_chart_action.ts index dff41ef2ead736..b8521914da1746 100644 --- a/x-pack/test/functional/apps/dashboard/group3/drilldowns/explore_data_chart_action.ts +++ b/x-pack/test/functional/apps/dashboard/group3/drilldowns/explore_data_chart_action.ts @@ -13,7 +13,7 @@ const ACTION_TEST_SUBJ = `embeddablePanelAction-${ACTION_ID}`; export default function ({ getService, getPageObjects }: FtrProviderContext) { const drilldowns = getService('dashboardDrilldownsManage'); - const { dashboard, discover, common, timePicker } = getPageObjects([ + const { dashboard, discover, timePicker } = getPageObjects([ 'dashboard', 'discover', 'common', @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Explore underlying data - chart action', () => { describe('value click action', () => { it('action exists in chart click popup menu', async () => { - await PageObjects.dashboard.navigateToApp(); + await dashboard.navigateToApp(); await dashboard.preserveCrossAppState(); await dashboard.loadSavedDashboard(drilldowns.DASHBOARD_WITH_PIE_CHART_NAME); await pieChart.clickOnPieSlice('160,000'); @@ -60,7 +60,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { let originalTimeRangeDurationHours: number | undefined; it('action exists in chart brush popup menu', async () => { - await PageObjects.dashboard.navigateToApp(); + await dashboard.navigateToApp(); await dashboard.preserveCrossAppState(); await dashboard.loadSavedDashboard(drilldowns.DASHBOARD_WITH_AREA_CHART_NAME); diff --git a/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts b/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts index d050a1a9013c66..4364e386b86372 100644 --- a/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts +++ b/x-pack/test/functional/apps/transform/creation/index_pattern/continuous_transform.ts @@ -6,6 +6,7 @@ */ import { TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants'; +import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; import type { FtrProviderContext } from '../../../../ftr_provider_context'; import { diff --git a/x-pack/test/functional/page_objects/tag_management_page.ts b/x-pack/test/functional/page_objects/tag_management_page.ts index 2dbff16429c93d..7e8fbd8346c1d0 100644 --- a/x-pack/test/functional/page_objects/tag_management_page.ts +++ b/x-pack/test/functional/page_objects/tag_management_page.ts @@ -239,7 +239,6 @@ class TagAssignmentFlyout extends FtrService { */ export class TagManagementPageObject extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); - private readonly find = this.ctx.getService('find'); private readonly browser = this.ctx.getService('browser'); private readonly retry = this.ctx.getService('retry'); private readonly header = this.ctx.getPageObject('header'); diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts index d8dad778fa03e6..e2db084b46276a 100644 --- a/x-pack/test/functional/services/ml/api.ts +++ b/x-pack/test/functional/services/ml/api.ts @@ -1504,9 +1504,8 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { async deleteIngestPipeline(modelId: string, usePrefix: boolean = true) { log.debug(`Deleting ingest pipeline for trained model with id "${modelId}"`); - const { body, status } = await esSupertest.delete( - `/_ingest/pipeline/${usePrefix ? 'pipeline_' : ''}${modelId}` - ); + // const { body, status } = + await esSupertest.delete(`/_ingest/pipeline/${usePrefix ? 'pipeline_' : ''}${modelId}`); // @todo // this.assertResponseStatusCode(200, status, body); From bb5439f4e1c3267625b1bc15210950ee2af63dfa Mon Sep 17 00:00:00 2001 From: mohamedhamed-ahmed Date: Wed, 27 Sep 2023 22:18:13 +0200 Subject: [PATCH 06/22] [Log Explorer] Show Filter controls in compressed style (#167402) closes https://github.com/elastic/kibana/issues/166440 This PR applies compressed style to the control group container. Screenshot 2023-09-27 at 14 44 51 --- .../customizations/custom_dataset_filters.tsx | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/log_explorer/public/customizations/custom_dataset_filters.tsx b/x-pack/plugins/log_explorer/public/customizations/custom_dataset_filters.tsx index 1f27f4a12b05ff..c315971fb23a5e 100644 --- a/x-pack/plugins/log_explorer/public/customizations/custom_dataset_filters.tsx +++ b/x-pack/plugins/log_explorer/public/customizations/custom_dataset_filters.tsx @@ -7,8 +7,8 @@ import React from 'react'; import { ControlGroupRenderer } from '@kbn/controls-plugin/public'; import { Query } from '@kbn/es-query'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { useControlPanels } from '../hooks/use_control_panels'; import { LogExplorerProfileStateService } from '../state_machines/log_explorer_profile'; @@ -42,8 +42,41 @@ const CustomDatasetFilters = ({ }; const ControlGroupContainer = euiStyled.div` - .controlGroup { - min-height: unset; +[class*='options_list_popover_footer--OptionsListPopoverFooter'] { + display: none; +} + +[data-test-subj='optionsListControl__sortingOptionsButton'] { + display: none; +} + +[id^='control-popover'] .euiPopoverTitle { + display: none; +} + + .euiFlexGroup.controlGroup { + min-height: 32px; + } + + .euiFormControlLayout.euiFormControlLayout--group.controlFrame__formControlLayout { + height: 32px; + + & .euiFormLabel.controlFrame__formControlLayoutLabel { + padding: 8px !important; + } + + .euiButtonEmpty.euiFilterButton { + height: 32px; + } + } + + .euiText.errorEmbeddableCompact__button { + padding: 8px; + + .euiLink { + display: flex; + gap: 8px; + } } `; From 7b4e6a6775cca077177546939a14042eac840098 Mon Sep 17 00:00:00 2001 From: christineweng <18648970+christineweng@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:19:25 -0500 Subject: [PATCH 07/22] [Security Solution] Expandable flyout - clean up loading states and no data messages (#166939) ## Summary This PR cleaned up the loading and empty state of most components in the new expandable alerts flyout: 1) Refactor `FlyoutLoading` component to be used across components 2) Updated unit tests to explicitly check no data messages 3) Changed loading spinner in smaller components to be skeleton text 4) Moved error/no data message to table 5) Added loading and/or error messages for: 1) Right panel -> about -> Rule description, note that rule preview is disabled if no rule is found ![image](https://github.com/elastic/kibana/assets/18648970/11cb7926-ff86-4deb-a9d1-993463fad466) 2) Right panel -> about -> Alert reason, note that the alert reason preview is disabled if no reason available ![image](https://github.com/elastic/kibana/assets/18648970/9674d81a-ca8b-4fea-981a-23c2cf3f3bfc) 3) Right panel -> Investigation -> Highlighted fields ![image](https://github.com/elastic/kibana/assets/18648970/d349251a-a027-409d-b94d-2792abe6543c) 4) Right panel -> Insights -> host and user preview ![image](https://github.com/elastic/kibana/assets/18648970/161340aa-4ca1-4205-9628-87206743f776) 5) Right panel -> Visualization -> analyzer preview (to match error in analyzer graph) ![image](https://github.com/elastic/kibana/assets/18648970/73b0018d-1f97-4fa3-be4d-b55afeb047b7) 6) Right panel -> About -> show rule summary & show alert reason when there is an error - Very uncommon because the button should be disabled if data is not available, adding as fall back ![image](https://github.com/elastic/kibana/assets/18648970/5088e9f8-bdd1-4e61-8878-dba756b44c32) ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../components/correlations_details.test.tsx | 15 ++- .../left/components/correlations_details.tsx | 18 ++-- .../left/components/entities_details.test.tsx | 27 ++---- .../left/components/entities_details.tsx | 12 +-- .../components/investigation_guide.test.tsx | 26 +++-- .../left/components/investigation_guide.tsx | 65 +++++-------- .../components/prevalence_details.test.tsx | 40 ++------ .../left/components/prevalence_details.tsx | 34 ++----- .../flyout/left/components/related_cases.tsx | 19 +--- .../left/components/response_details.test.tsx | 12 +-- .../left/components/response_details.tsx | 2 +- .../public/flyout/left/components/test_ids.ts | 11 +-- .../threat_intelligence_details.tsx | 44 ++++----- .../components/alert_reason_preview.test.tsx | 15 +++ .../components/alert_reason_preview.tsx | 7 +- .../preview/components/rule_preview.test.tsx | 9 +- .../preview/components/rule_preview.tsx | 16 +++- .../components/analyzer_preview.test.tsx | 20 +++- .../right/components/analyzer_preview.tsx | 53 ++++++---- .../analyzer_preview_container.test.tsx | 26 ++--- .../components/analyzer_preview_container.tsx | 42 ++++---- .../components/correlations_overview.test.tsx | 18 ++-- .../components/correlations_overview.tsx | 12 +-- .../right/components/description.test.tsx | 86 ++++++++++------- .../flyout/right/components/description.tsx | 59 +++++++----- .../components/entities_overview.test.tsx | 23 ++--- .../right/components/entities_overview.tsx | 12 +-- .../components/highlighted_fields.test.tsx | 9 +- .../right/components/highlighted_fields.tsx | 19 ++-- .../components/host_entity_overview.test.tsx | 28 ++++++ .../right/components/host_entity_overview.tsx | 75 +++++++++------ .../components/investigation_guide.test.tsx | 26 +++-- .../right/components/investigation_guide.tsx | 48 ++++------ .../flyout/right/components/mitre_attack.tsx | 1 + .../components/prevalence_overview.test.tsx | 20 ++-- .../right/components/prevalence_overview.tsx | 12 +-- .../flyout/right/components/reason.test.tsx | 12 +-- .../public/flyout/right/components/reason.tsx | 16 +++- .../session_preview_container.test.tsx | 53 +++++----- .../components/session_preview_container.tsx | 96 +++++++++---------- .../flyout/right/components/test_ids.ts | 19 ++-- .../threat_intelligence_overview.test.tsx | 4 +- .../threat_intelligence_overview.tsx | 3 +- .../components/user_entity_overview.test.tsx | 31 ++++++ .../right/components/user_entity_overview.tsx | 71 +++++++++----- .../shared/components/expandable_panel.tsx | 16 ++-- .../shared/components/flyout_loading.test.tsx | 6 ++ .../shared/components/flyout_loading.tsx | 15 ++- ..._details_left_panel_session_view_tab.cy.ts | 11 +-- .../alert_details_left_panel_response_tab.ts | 7 +- ...ert_details_left_panel_session_view_tab.ts | 4 - 51 files changed, 702 insertions(+), 623 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx index 2bbfa8f4ab7c50..c6efa418f90796 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx @@ -20,7 +20,6 @@ import { CORRELATIONS_DETAILS_BY_SESSION_SECTION_TABLE_TEST_ID, CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID, CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID, - CORRELATIONS_DETAILS_NO_DATA_TEST_ID, CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID, } from './test_ids'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; @@ -53,12 +52,13 @@ const renderCorrelationDetails = () => { ); }; - const CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID ); +const NO_DATA_MESSAGE = 'No correlations data available.'; + describe('CorrelationsDetails', () => { beforeEach(() => { jest.clearAllMocks(); @@ -102,14 +102,14 @@ describe('CorrelationsDetails', () => { dataCount: 1, }); - const { getByTestId, queryByTestId } = renderCorrelationDetails(); + const { getByTestId, queryByText } = renderCorrelationDetails(); expect(getByTestId(CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_BY_SESSION_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should render no section and show error message if show values are false', () => { @@ -125,7 +125,7 @@ describe('CorrelationsDetails', () => { jest.mocked(useShowRelatedCases).mockReturnValue(false); jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); - const { getByTestId, queryByTestId } = renderCorrelationDetails(); + const { getByText, queryByTestId } = renderCorrelationDetails(); expect( queryByTestId(CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TABLE_TEST_ID) @@ -140,10 +140,7 @@ describe('CorrelationsDetails', () => { expect( queryByTestId(CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID) ).not.toBeInTheDocument(); - expect(getByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( - 'No correlations data available.' - ); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should render no section if values are null', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx index f7def1d23ac98b..03020832365327 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx @@ -6,9 +6,9 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiPanel, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { CORRELATIONS_DETAILS_NO_DATA_TEST_ID } from './test_ids'; +import { CORRELATIONS_DETAILS_TEST_ID } from './test_ids'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { RelatedAlertsBySameSourceEvent } from './related_alerts_by_same_source_event'; import { RelatedCases } from './related_cases'; @@ -56,7 +56,7 @@ export const CorrelationsDetails: React.FC = () => { showSuppressedAlerts; return ( - <> + {canShowAtLeastOneInsight ? ( {showSuppressedAlerts && ( @@ -98,14 +98,12 @@ export const CorrelationsDetails: React.FC = () => { )} ) : ( -

- -

+ )} - +
); }; diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx index 2ecda17c128ba7..17a94e7d05c255 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx @@ -11,12 +11,7 @@ import '@testing-library/jest-dom'; import { LeftPanelContext } from '../context'; import { TestProviders } from '../../../common/mock'; import { EntitiesDetails } from './entities_details'; -import { - ENTITIES_DETAILS_NO_DATA_TEST_ID, - ENTITIES_DETAILS_TEST_ID, - HOST_DETAILS_TEST_ID, - USER_DETAILS_TEST_ID, -} from './test_ids'; +import { ENTITIES_DETAILS_TEST_ID, HOST_DETAILS_TEST_ID, USER_DETAILS_TEST_ID } from './test_ids'; import { mockContextValue } from '../mocks/mock_context'; import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '../../shared/components/test_ids'; @@ -40,6 +35,8 @@ jest.mock('react-redux', () => { const USER_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(USER_DETAILS_TEST_ID); const HOST_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(HOST_DETAILS_TEST_ID); +const NO_DATA_MESSAGE = 'Host and user information are unavailable for this alert.'; + const renderEntitiesDetails = (contextValue: LeftPanelContext) => render( @@ -51,11 +48,11 @@ const renderEntitiesDetails = (contextValue: LeftPanelContext) => describe('', () => { it('renders entities details correctly', () => { - const { getByTestId, queryByTestId } = renderEntitiesDetails(mockContextValue); + const { getByTestId, queryByText } = renderEntitiesDetails(mockContextValue); expect(getByTestId(ENTITIES_DETAILS_TEST_ID)).toBeInTheDocument(); expect(getByTestId(USER_TEST_ID)).toBeInTheDocument(); expect(getByTestId(HOST_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should render no data message if user name and host name are not available', () => { @@ -64,11 +61,8 @@ describe('', () => { getFieldsData: (fieldName: string) => fieldName === '@timestamp' ? ['2022-07-25T08:20:18.966Z'] : [], }; - const { getByTestId, queryByTestId } = renderEntitiesDetails(contextValue); - expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( - 'Host and user information are unavailable for this alert.' - ); + const { getByText, queryByTestId } = renderEntitiesDetails(contextValue); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); expect(queryByTestId(USER_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(HOST_TEST_ID)).not.toBeInTheDocument(); }); @@ -87,11 +81,8 @@ describe('', () => { } }, }; - const { getByTestId, queryByTestId } = renderEntitiesDetails(contextValue); - expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( - 'Host and user information are unavailable for this alert.' - ); + const { getByText, queryByTestId } = renderEntitiesDetails(contextValue); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); expect(queryByTestId(USER_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(HOST_TEST_ID)).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx index 78ee6485811620..5821e3bec17c80 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx @@ -12,7 +12,7 @@ import { useLeftPanelContext } from '../context'; import { getField } from '../../shared/utils'; import { UserDetails } from './user_details'; import { HostDetails } from './host_details'; -import { ENTITIES_DETAILS_NO_DATA_TEST_ID, ENTITIES_DETAILS_TEST_ID } from './test_ids'; +import { ENTITIES_DETAILS_TEST_ID } from './test_ids'; export const ENTITIES_TAB_ID = 'entities-details'; @@ -45,12 +45,10 @@ export const EntitiesDetails: React.FC = () => { )} ) : ( -

- -

+ )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx index 37d91600bbe5ef..f628fac332c6d3 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx @@ -10,15 +10,15 @@ import { render } from '@testing-library/react'; import { InvestigationGuide } from './investigation_guide'; import { LeftPanelContext } from '../context'; import { TestProviders } from '../../../common/mock'; -import { - INVESTIGATION_GUIDE_LOADING_TEST_ID, - INVESTIGATION_GUIDE_NO_DATA_TEST_ID, -} from './test_ids'; +import { INVESTIGATION_GUIDE_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID } from './test_ids'; import { mockContextValue } from '../mocks/mock_context'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; jest.mock('../../shared/hooks/use_investigation_guide'); +const NO_DATA_TEXT = + "There's no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one."; + const renderInvestigationGuide = (context: LeftPanelContext = mockContextValue) => ( @@ -35,8 +35,10 @@ describe('', () => { basicAlertData: { ruleId: 'ruleId' }, ruleNote: 'test note', }); - const { queryByTestId } = render(renderInvestigationGuide()); - expect(queryByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + + const { queryByTestId, getByText, queryByText } = render(renderInvestigationGuide()); + expect(getByText('test note')).toBeInTheDocument(); + expect(queryByText(NO_DATA_TEXT)).not.toBeInTheDocument(); expect(queryByTestId(INVESTIGATION_GUIDE_LOADING_TEST_ID)).not.toBeInTheDocument(); }); @@ -54,10 +56,7 @@ describe('', () => { ruleNote: 'test note', }); const { getByTestId } = render(renderInvestigationGuide()); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( - `There’s no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one.` - ); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_TEXT); }); it('should render no data message when there is no rule note', () => { @@ -66,10 +65,7 @@ describe('', () => { ruleNote: undefined, }); const { getByTestId } = render(renderInvestigationGuide()); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( - `There’s no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one.` - ); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_TEXT); }); it('should render no data message when useInvestigationGuide errors out', () => { @@ -78,6 +74,6 @@ describe('', () => { error: true, }); const { getByTestId } = render(renderInvestigationGuide()); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_TEXT); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx index 1152e11df6ba62..4c6452093f5e81 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx @@ -5,15 +5,13 @@ * 2.0. */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; import { useLeftPanelContext } from '../context'; -import { - INVESTIGATION_GUIDE_LOADING_TEST_ID, - INVESTIGATION_GUIDE_NO_DATA_TEST_ID, -} from './test_ids'; +import { INVESTIGATION_GUIDE_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID } from './test_ids'; import { InvestigationGuideView } from '../../../common/components/event_details/investigation_guide_view'; +import { FlyoutLoading } from '../../shared/components/flyout_loading'; /** * Investigation guide displayed in the left panel. @@ -26,22 +24,11 @@ export const InvestigationGuide: React.FC = () => { dataFormattedForFieldBrowser, }); - if (loading) { - return ( - - - - - - ); - } - return ( - <> - {!error && basicAlertData.ruleId && ruleNote ? ( +
+ {loading ? ( + + ) : !error && basicAlertData.ruleId && ruleNote ? ( { showFullView={true} /> ) : ( -

- - - - ), - }} - /> -

+ + + + ), + }} + /> )} - +
); }; diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx index c202d7eab97686..9a1181fe006411 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx @@ -10,12 +10,10 @@ import React from 'react'; import { LeftPanelContext } from '../context'; import { PrevalenceDetails } from './prevalence_details'; import { - PREVALENCE_DETAILS_LOADING_TEST_ID, PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, - PREVALENCE_DETAILS_NO_DATA_TEST_ID, PREVALENCE_DETAILS_TABLE_TEST_ID, PREVALENCE_DETAILS_UPSELL_TEST_ID, PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, @@ -47,6 +45,8 @@ jest.mock('../../../common/hooks/use_license', () => { }; }); +const NO_DATA_MESSAGE = 'No prevalence data available.'; + const panelContextValue = { eventId: 'event id', indexName: 'indexName', @@ -96,7 +96,7 @@ describe('PrevalenceDetails', () => { ], }); - const { getByTestId, getAllByTestId, queryByTestId } = renderPrevalenceDetails(); + const { getByTestId, getAllByTestId, queryByTestId, queryByText } = renderPrevalenceDetails(); expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID).length).toBeGreaterThan(1); @@ -114,7 +114,7 @@ describe('PrevalenceDetails', () => { getAllByTestId(PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID).length ).toBeGreaterThan(1); expect(queryByTestId(PREVALENCE_DETAILS_UPSELL_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should render formatted numbers for the alert and document count columns', () => { @@ -201,20 +201,6 @@ describe('PrevalenceDetails', () => { expect(getByTestId(PREVALENCE_DETAILS_UPSELL_TEST_ID)).toBeInTheDocument(); }); - it('should render loading', () => { - (usePrevalence as jest.Mock).mockReturnValue({ - loading: true, - error: false, - data: [], - }); - - const { getByTestId, queryByTestId } = renderPrevalenceDetails(); - - expect(getByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(PREVALENCE_DETAILS_UPSELL_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); - }); - it('should render no data message if call errors out', () => { (usePrevalence as jest.Mock).mockReturnValue({ loading: false, @@ -222,13 +208,8 @@ describe('PrevalenceDetails', () => { data: [], }); - const { getByTestId, queryByTestId } = renderPrevalenceDetails(); - - expect(getByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( - 'No prevalence data available.' - ); - expect(queryByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).not.toBeInTheDocument(); + const { getByText } = renderPrevalenceDetails(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should render no data message if no data', () => { @@ -238,12 +219,7 @@ describe('PrevalenceDetails', () => { data: [], }); - const { getByTestId, queryByTestId } = renderPrevalenceDetails(); - - expect(getByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(PREVALENCE_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( - 'No prevalence data available.' - ); - expect(queryByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).not.toBeInTheDocument(); + const { getByText } = renderPrevalenceDetails(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx index 4af7c2feeeb464..9ddae380c91362 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx @@ -14,7 +14,6 @@ import { EuiFlexItem, EuiInMemoryTable, EuiLink, - EuiLoadingSpinner, EuiPanel, EuiSpacer, EuiSuperDatePicker, @@ -28,14 +27,12 @@ import { InvestigateInTimelineButton } from '../../../common/components/event_de import type { PrevalenceData } from '../../shared/hooks/use_prevalence'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { - PREVALENCE_DETAILS_LOADING_TEST_ID, PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, - PREVALENCE_DETAILS_NO_DATA_TEST_ID, PREVALENCE_DETAILS_DATE_PICKER_TEST_ID, PREVALENCE_DETAILS_TABLE_TEST_ID, PREVALENCE_DETAILS_UPSELL_TEST_ID, @@ -319,19 +316,6 @@ export const PrevalenceDetails: React.FC = () => { [data, absoluteStart, absoluteEnd] ); - if (loading) { - return ( - - - - - - ); - } - const upsell = ( <> @@ -366,20 +350,18 @@ export const PrevalenceDetails: React.FC = () => { width="full" /> - {data.length > 0 ? ( - - ) : ( -

+ -

- )} + } + /> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx index 681d542eac3a1b..54c96effd60e83 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx @@ -7,10 +7,9 @@ import React from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiInMemoryTable, EuiSkeletonText } from '@elastic/eui'; +import { EuiInMemoryTable } from '@elastic/eui'; import type { RelatedCase } from '@kbn/cases-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import { CaseDetailsLink } from '../../../common/components/links'; import { @@ -65,22 +64,6 @@ export interface RelatedCasesProps { export const RelatedCases: React.VFC = ({ eventId }) => { const { loading, error, data, dataCount } = useFetchRelatedCases({ eventId }); - if (loading) { - return ( - - ); - } - if (error) { return null; } diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx index cea5e630036622..dc6f3168eccadc 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx @@ -10,7 +10,7 @@ import { render } from '@testing-library/react'; import '@testing-library/jest-dom'; import { LeftPanelContext } from '../context'; import { rawEventData, TestProviders } from '../../../common/mock'; -import { RESPONSE_DETAILS_TEST_ID, RESPONSE_NO_DATA_TEST_ID } from './test_ids'; +import { RESPONSE_DETAILS_TEST_ID } from './test_ids'; import { ResponseDetails } from './response_details'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; @@ -59,6 +59,9 @@ jest.mock('../../../common/lib/kibana', () => { }; }); +const NO_DATA_MESSAGE = + "There are no response actions defined for this event. To add some, edit the rule's settings and set up response actionsExternal link(opens in a new tab or window)."; + const defaultContextValue = { dataAsNestedObject: { _id: 'test', @@ -114,7 +117,7 @@ describe('', () => { expect(wrapper.getByTestId('responseActionsViewWrapper')).toBeInTheDocument(); expect(wrapper.queryByTestId('osqueryViewWrapper')).not.toBeInTheDocument(); - expect(wrapper.queryByTestId(RESPONSE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(wrapper.getByTestId(RESPONSE_DETAILS_TEST_ID)).not.toHaveTextContent(NO_DATA_MESSAGE); }); it('should render the view with osquery only', () => { @@ -135,9 +138,6 @@ describe('', () => { expect(wrapper.queryByTestId('responseActionsViewWrapper')).not.toBeInTheDocument(); expect(wrapper.queryByTestId('osqueryViewWrapper')).not.toBeInTheDocument(); - expect(wrapper.getByTestId(RESPONSE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(wrapper.getByTestId(RESPONSE_NO_DATA_TEST_ID)).toHaveTextContent( - 'There are no response actions defined for this event. To add some, edit the rule’s settings and set up response actionsExternal link(opens in a new tab or window).' - ); + expect(wrapper.getByTestId(RESPONSE_DETAILS_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx index 9e813b518a9f61..06bb1096e3d988 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx @@ -69,7 +69,7 @@ export const ResponseDetails: React.FC = () => { { setRange, } = useThreatIntelligenceDetails(); - if (isEventDataLoading) { - return ( - - - - - - ); - } - - return ( - <> - - <> - - - - - + return isEventDataLoading ? ( + + ) : ( + + <> + + + + ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx index 51feb8ce9d37ff..1408a5f6586306 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx @@ -21,6 +21,8 @@ const panelContextValue = { ...mockContextValue, }; +const NO_DATA_MESSAGE = 'There was an error displaying data.'; + describe('', () => { it('should render alert reason preview', () => { const { getByTestId } = render( @@ -35,4 +37,17 @@ describe('', () => { expect(getByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).toBeInTheDocument(); expect(getByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).toHaveTextContent('Alert reason'); }); + + it('should render no data message if alert reason is not available', () => { + const { getByText } = render( + + + + + + + + ); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx index 476a1f3551948f..3702160339b063 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx @@ -14,6 +14,7 @@ import { ALERT_REASON_PREVIEW_BODY_TEST_ID } from './test_ids'; import { usePreviewPanelContext } from '../context'; import { getRowRenderer } from '../../../timelines/components/timeline/body/renderers/get_row_renderer'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; +import { FlyoutError } from '../../shared/components/flyout_error'; const ReasonPreviewContainerWrapper = styled.div` overflow-x: auto; @@ -47,7 +48,11 @@ export const AlertReasonPreview: React.FC = () => { ); if (!renderer) { - return null; + return ( + + + + ); } return ( diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx index bc3f6c5e8f8e3e..9a76a852b5a924 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx @@ -67,11 +67,9 @@ const renderRulePreview = () =>
); -describe('', () => { - beforeEach(() => { - // (useAppToasts as jest.Mock).mockReturnValue(useAppToastsValueMock); - }); +const NO_DATA_MESSAGE = 'There was an error displaying data.'; +describe('', () => { afterEach(() => { jest.clearAllMocks(); }); @@ -134,9 +132,10 @@ describe('', () => { it('should not render rule preview when rule is null', async () => { mockUseRuleWithFallback.mockReturnValue({}); - const { queryByTestId } = renderRulePreview(); + const { queryByTestId, getByText } = renderRulePreview(); await act(async () => { expect(queryByTestId(RULE_PREVIEW_BODY_TEST_ID)).not.toBeInTheDocument(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx index db87a9a681902c..84448aea0eb492 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React, { memo, useState, useEffect } from 'react'; -import { EuiText, EuiHorizontalRule, EuiSpacer, EuiPanel, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiText, EuiHorizontalRule, EuiSpacer, EuiPanel } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '../../../common/lib/kibana'; import { useGetSavedQuery } from '../../../detections/pages/detection_engine/rules/use_get_saved_query'; @@ -19,6 +19,8 @@ import { StepAboutRuleReadOnly } from '../../../detections/components/rules/step import { StepDefineRuleReadOnly } from '../../../detections/components/rules/step_define_rule'; import { StepScheduleRuleReadOnly } from '../../../detections/components/rules/step_schedule_rule'; import { StepRuleActionsReadOnly } from '../../../detections/components/rules/step_rule_actions'; +import { FlyoutLoading } from '../../shared/components/flyout_loading'; +import { FlyoutError } from '../../shared/components/flyout_error'; import { RULE_PREVIEW_BODY_TEST_ID, RULE_PREVIEW_ABOUT_TEST_ID, @@ -79,7 +81,9 @@ export const RulePreview: React.FC = memo(() => { const hasResponseActions = Boolean(ruleActionsData?.responseActions?.length); const hasActions = ruleActionsData != null && (hasNotificationActions || hasResponseActions); - return rule ? ( + return ruleLoading ? ( + + ) : rule ? ( @@ -169,9 +173,11 @@ export const RulePreview: React.FC = memo(() => { )} - ) : ruleLoading ? ( - - ) : null; + ) : ( + + + + ); }); RulePreview.displayName = 'RulePreview'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.test.tsx index 780bea57d1f096..dabc988aa2807f 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.test.tsx @@ -30,6 +30,8 @@ const renderAnalyzerPreview = (contextValue: RightPanelContext) =>
); +const NO_DATA_MESSAGE = 'An error is preventing this alert from being analyzed.'; + describe('', () => { beforeEach(() => { jest.resetAllMocks(); @@ -57,7 +59,7 @@ describe('', () => { expect(wrapper.getByTestId(ANALYZER_PREVIEW_TEST_ID)).toBeInTheDocument(); }); - it('does not show analyzer preview when documentId and index are not present', () => { + it('shows error message when documentid and index are not present', () => { mockUseAlertPrevalenceFromProcessTree.mockReturnValue({ loading: false, error: false, @@ -76,13 +78,25 @@ describe('', () => { }, ], }; - const { queryByTestId } = renderAnalyzerPreview(contextValue); + const { getByText } = renderAnalyzerPreview(contextValue); expect(mockUseAlertPrevalenceFromProcessTree).toHaveBeenCalledWith({ isActiveTimeline: false, documentId: '', indices: [], }); - expect(queryByTestId(ANALYZER_PREVIEW_TEST_ID)).not.toBeInTheDocument(); + + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); + }); + + it('shows error message when there is an error', () => { + mockUseAlertPrevalenceFromProcessTree.mockReturnValue({ + loading: false, + error: true, + alertIds: undefined, + statsNodes: undefined, + }); + const { getByText } = renderAnalyzerPreview(mockContextValue); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx index 42749285de6125..5d4a21fca293b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx @@ -6,9 +6,10 @@ */ import React, { useEffect, useMemo, useState } from 'react'; import { find } from 'lodash/fp'; -import { EuiTreeView } from '@elastic/eui'; +import { EuiTreeView, EuiSkeletonText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { ANALYZER_PREVIEW_TEST_ID, ANALYZER_PREVIEW_LOADING_TEST_ID } from './test_ids'; import { getTreeNodes } from '../utils/analyzer_helpers'; import { ANCESTOR_ID, RULE_INDICES } from '../../shared/constants/field_names'; import { useRightPanelContext } from '../context'; @@ -41,7 +42,7 @@ export const AnalyzerPreview: React.FC = () => { const index = find({ category: 'kibana', field: RULE_INDICES }, data); const indices = index?.values ?? []; - const { statsNodes } = useAlertPrevalenceFromProcessTree({ + const { statsNodes, loading, error } = useAlertPrevalenceFromProcessTree({ isActiveTimeline: isActiveTimeline(scopeId), documentId: processDocumentId, indices, @@ -58,24 +59,36 @@ export const AnalyzerPreview: React.FC = () => { [cache.statsNodes] ); - if (!documentId || !index || !items || items.length === 0) { - return null; - } + const showAnalyzerTree = documentId && index && items && items.length > 0 && !error; - return ( -
- -
+ return loading ? ( + + ) : showAnalyzerTree ? ( + + ) : ( + ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx index 60e17a0bf8433b..2adbf4e01d7050 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx @@ -9,9 +9,10 @@ import { render, screen } from '@testing-library/react'; import { TestProviders } from '../../../common/mock'; import React from 'react'; import { RightPanelContext } from '../context'; +import { mockContextValue } from '../mocks/mock_context'; import { AnalyzerPreviewContainer } from './analyzer_preview_container'; import { isInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; -import { ANALYZER_PREVIEW_NO_DATA_TEST_ID, ANALYZER_PREVIEW_TEST_ID } from './test_ids'; +import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { useAlertPrevalenceFromProcessTree } from '../../../common/containers/alerts/use_alert_prevalence_from_process_tree'; import * as mock from '../mocks/mock_analyzer_data'; import { @@ -42,9 +43,13 @@ jest.mock('react-redux', () => { }; }); +const NO_ANALYZER_MESSAGE = + 'You can only visualize events triggered by hosts configured with the Elastic Defend integration or any sysmon data from winlogbeat. Refer to Visual event analyzerExternal link(opens in a new tab or window) for more information.'; + const panelContextValue = { + ...mockContextValue, dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, -} as unknown as RightPanelContext; +}; const renderAnalyzerPreview = () => render( @@ -72,10 +77,9 @@ describe('AnalyzerPreviewContainer', () => { investigateInTimelineAlertClick: jest.fn(), }); - const { getByTestId, queryByTestId } = renderAnalyzerPreview(); + const { getByTestId } = renderAnalyzerPreview(); expect(getByTestId(ANALYZER_PREVIEW_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) ).toBeInTheDocument(); @@ -91,6 +95,9 @@ describe('AnalyzerPreviewContainer', () => { expect( screen.queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) ).not.toBeInTheDocument(); + expect( + screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) + ).not.toHaveTextContent(NO_ANALYZER_MESSAGE); }); it('should render error message and text in header', () => { @@ -99,16 +106,13 @@ describe('AnalyzerPreviewContainer', () => { investigateInTimelineAlertClick: jest.fn(), }); - const { getByTestId, queryByTestId } = renderAnalyzerPreview(); - - expect(queryByTestId(ANALYZER_PREVIEW_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).toHaveTextContent( - 'You can only visualize events triggered by hosts configured with the Elastic Defend integration or any sysmon data from winlogbeat. Refer to Visual event analyzerExternal link(opens in a new tab or window) for more information.' - ); + const { getByTestId } = renderAnalyzerPreview(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) ).toBeInTheDocument(); + expect( + getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) + ).toHaveTextContent(NO_ANALYZER_MESSAGE); }); it('should navigate to left section Visualize tab when clicking on title', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx index b059bcd1138d01..ed575481fabd91 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx @@ -18,7 +18,7 @@ import { setActiveTabTimeline } from '../../../timelines/store/timeline/actions' import { useRightPanelContext } from '../context'; import { isInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; import { AnalyzerPreview } from './analyzer_preview'; -import { ANALYZER_PREVIEW_NO_DATA_TEST_ID, ANALYZER_PREVIEW_TEST_ID } from './test_ids'; +import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; const timelineId = 'timeline-1'; @@ -81,27 +81,25 @@ export const AnalyzerPreviewContainer: React.FC = () => { {isEnabled ? ( ) : ( -

- {'sysmon'}, - winlogbeat: {'winlogbeat'}, - link: ( - - - - ), - }} - /> -

+ {'sysmon'}, + winlogbeat: {'winlogbeat'}, + link: ( + + + + ), + }} + /> )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx index ec94fffd9bbe02..9d1a73e5bd6160 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx @@ -14,7 +14,6 @@ import { CorrelationsOverview } from './correlations_overview'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { - CORRELATIONS_NO_DATA_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, @@ -82,6 +81,8 @@ const renderCorrelationsOverview = (contextValue: RightPanelContext) => ( ); +const NO_DATA_MESSAGE = 'No correlations data available.'; + describe('', () => { it('should render wrapper component', () => { jest.mocked(useShowRelatedAlertsByAncestry).mockReturnValue({ show: false }); @@ -131,13 +132,13 @@ describe('', () => { dataCount: 1, }); - const { getByTestId, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); + const { getByTestId, queryByText } = render(renderCorrelationsOverview(panelContextValue)); expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_CASES_TEST_ID)).toBeInTheDocument(); expect(getByTestId(SUPPRESSED_ALERTS_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(CORRELATIONS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should hide rows and show error message if show values are false', () => { @@ -153,16 +154,13 @@ describe('', () => { jest.mocked(useShowRelatedCases).mockReturnValue(false); jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); - const { getByTestId, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); + const { getByText, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(CORRELATIONS_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(CORRELATIONS_NO_DATA_TEST_ID)).toHaveTextContent( - 'No correlations data available.' - ); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should hide rows if values are null', () => { @@ -172,13 +170,13 @@ describe('', () => { jest.mocked(useShowRelatedCases).mockReturnValue(false); jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); - const { queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); + const { queryByTestId, queryByText } = render(renderCorrelationsOverview(panelContextValue)); expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(CORRELATIONS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should navigate to the left section Insights tab when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx index 1911d3a6fb5dda..84349b2b8e523c 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx @@ -20,7 +20,7 @@ import { SuppressedAlerts } from './suppressed_alerts'; import { useShowSuppressedAlerts } from '../../shared/hooks/use_show_suppressed_alerts'; import { RelatedCases } from './related_cases'; import { useShowRelatedCases } from '../../shared/hooks/use_show_related_cases'; -import { CORRELATIONS_NO_DATA_TEST_ID, CORRELATIONS_TEST_ID } from './test_ids'; +import { CORRELATIONS_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; @@ -120,12 +120,10 @@ export const CorrelationsOverview: React.FC = () => { )} ) : ( -

- -

+ )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx index 3dc09a7ac598f3..2cf9276a1853ee 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx @@ -8,7 +8,11 @@ import React from 'react'; import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; -import { DESCRIPTION_TITLE_TEST_ID, RULE_SUMMARY_BUTTON_TEST_ID } from './test_ids'; +import { + DESCRIPTION_TITLE_TEST_ID, + RULE_SUMMARY_BUTTON_TEST_ID, + DESCRIPTION_DETAILS_TEST_ID, +} from './test_ids'; import { Description } from './description'; import { RightPanelContext } from '../context'; import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; @@ -64,6 +68,8 @@ const renderDescription = (panelContext: RightPanelContext) => ); +const NO_DATA_MESSAGE = "There's no description for this rule."; + describe('', () => { it('should render the component', () => { const { getByTestId } = renderDescription( @@ -72,17 +78,15 @@ describe('', () => { expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Rule description'); + expect(getByTestId(DESCRIPTION_DETAILS_TEST_ID)).toHaveTextContent(ruleDescription.values[0]); expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toBeInTheDocument(); }); - it('should not render rule preview button if rule name is not available', () => { - const { getByTestId, queryByTestId } = renderDescription( - panelContextValue([ruleUuid, ruleDescription]) - ); + it('should render no data message if rule description is not available', () => { + const { getByTestId, getByText } = renderDescription(panelContextValue([ruleUuid])); - expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Rule description'); - expect(queryByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(DESCRIPTION_DETAILS_TEST_ID)).toBeInTheDocument(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should render document title if document is not an alert', () => { @@ -92,32 +96,48 @@ describe('', () => { expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Document description'); }); - it('should open preview panel when clicking on button', () => { - const panelContext = panelContextValue([ruleUuid, ruleDescription, ruleName]); - - const { getByTestId } = renderDescription(panelContext); - - getByTestId(RULE_SUMMARY_BUTTON_TEST_ID).click(); - - expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ - id: PreviewPanelKey, - path: { tab: 'rule-preview' }, - params: { - id: panelContext.eventId, - indexName: panelContext.indexName, - scopeId: panelContext.scopeId, - banner: { - title: ( - - ), - backgroundColor: 'warning', - textColor: 'warning', + describe('rule preview', () => { + it('should render rule preview button as disabled if rule name is not available', () => { + const { getByTestId } = renderDescription(panelContextValue([ruleUuid, ruleDescription])); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toHaveAttribute('disabled'); + }); + + it('should render rule preview button as disabled if rule id is not available', () => { + const { getByTestId } = renderDescription( + panelContextValue([{ ...ruleUuid, values: [] }, ruleName, ruleDescription]) + ); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toHaveAttribute('disabled'); + }); + + it('should open preview panel when clicking on button', () => { + const panelContext = panelContextValue([ruleUuid, ruleDescription, ruleName]); + + const { getByTestId } = renderDescription(panelContext); + + getByTestId(RULE_SUMMARY_BUTTON_TEST_ID).click(); + + expect(flyoutContextValue.openPreviewPanel).toHaveBeenCalledWith({ + id: PreviewPanelKey, + path: { tab: 'rule-preview' }, + params: { + id: panelContext.eventId, + indexName: panelContext.indexName, + scopeId: panelContext.scopeId, + banner: { + title: ( + + ), + backgroundColor: 'warning', + textColor: 'warning', + }, + ruleId: ruleUuid.values[0], }, - ruleId: ruleUuid.values[0], - }, + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx index 4b0169eeacbc22..d180d58db2a228 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx @@ -56,34 +56,41 @@ export const Description: FC = () => { }, [eventId, openPreviewPanel, indexName, scopeId, ruleId]); const viewRule = useMemo( - () => - !isEmpty(ruleName) && - !isEmpty(ruleId) && ( - - - - - - ), + () => ( + + + + + + ), [ruleName, openRulePreview, ruleId] ); - const hasRuleDescription = ruleDescription && ruleDescription.length > 0; + const alertRuleDescription = + ruleDescription?.length > 0 ? ( + ruleDescription + ) : ( + + ); return ( @@ -112,7 +119,7 @@ export const Description: FC = () => { - {hasRuleDescription ? ruleDescription : '-'} + {isAlert ? alertRuleDescription : '-'} ); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx index ea66a0da11f171..877d4053622bbb 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx @@ -11,7 +11,6 @@ import { RightPanelContext } from '../context'; import { ENTITIES_HOST_OVERVIEW_TEST_ID, ENTITIES_USER_OVERVIEW_TEST_ID, - INSIGHTS_ENTITIES_NO_DATA_TEST_ID, INSIGHTS_ENTITIES_TEST_ID, } from './test_ids'; import { EntitiesOverview } from './entities_overview'; @@ -45,6 +44,8 @@ const renderEntitiesOverview = (contextValue: RightPanelContext) => ); +const NO_DATA_MESSAGE = 'Host and user information are unavailable for this alert.'; + describe('', () => { it('should render wrapper component', () => { const { getByTestId, queryByTestId } = renderEntitiesOverview(mockContextValue); @@ -57,10 +58,10 @@ describe('', () => { }); it('should render user and host', () => { - const { getByTestId, queryByTestId } = renderEntitiesOverview(mockContextValue); + const { getByTestId, queryByText } = renderEntitiesOverview(mockContextValue); expect(getByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(getByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should only render user when host name is null', () => { @@ -69,11 +70,11 @@ describe('', () => { getFieldsData: (field: string) => (field === 'user.name' ? 'user1' : null), } as unknown as RightPanelContext; - const { queryByTestId, getByTestId } = renderEntitiesOverview(contextValue); + const { queryByTestId, getByTestId, queryByText } = renderEntitiesOverview(contextValue); expect(getByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(queryByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should only render host when user name is null', () => { @@ -82,11 +83,11 @@ describe('', () => { getFieldsData: (field: string) => (field === 'host.name' ? 'host1' : null), } as unknown as RightPanelContext; - const { queryByTestId, getByTestId } = renderEntitiesOverview(contextValue); + const { queryByTestId, getByTestId, queryByText } = renderEntitiesOverview(contextValue); expect(getByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(queryByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should render no data message if both host name and user name are null/blank', () => { @@ -95,11 +96,7 @@ describe('', () => { getFieldsData: (field: string) => {}, } as unknown as RightPanelContext; - const { queryByTestId } = renderEntitiesOverview(contextValue); - - expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).toHaveTextContent( - 'Host and user information are unavailable for this alert.' - ); + const { getByText } = renderEntitiesOverview(contextValue); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx index 52ac44137a1d64..38d9a25437e812 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx @@ -9,7 +9,7 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; -import { INSIGHTS_ENTITIES_NO_DATA_TEST_ID, INSIGHTS_ENTITIES_TEST_ID } from './test_ids'; +import { INSIGHTS_ENTITIES_TEST_ID } from './test_ids'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { useRightPanelContext } from '../context'; import { getField } from '../../shared/utils'; @@ -80,12 +80,10 @@ export const EntitiesOverview: React.FC = () => { )} ) : ( -

- -

+ )} diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.test.tsx index 4f4c750c8d39c0..47754818704dd7 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.test.tsx @@ -27,6 +27,8 @@ const renderHighlightedFields = (contextValue: RightPanelContext) => ); +const NO_DATA_MESSAGE = "There's no highlighted fields for this alert."; + describe('', () => { beforeEach(() => { (useRuleWithFallback as jest.Mock).mockReturnValue({ investigation_fields: undefined }); @@ -49,15 +51,14 @@ describe('', () => { expect(getByTestId(HIGHLIGHTED_FIELDS_DETAILS_TEST_ID)).toBeInTheDocument(); }); - it(`should render empty component if there aren't any highlighted fields`, () => { + it(`should render no data message if there aren't any highlighted fields`, () => { const contextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, scopeId: 'scopeId', } as unknown as RightPanelContext; (useHighlightedFields as jest.Mock).mockReturnValue({}); - const { container } = renderHighlightedFields(contextValue); - - expect(container).toBeEmptyDOMElement(); + const { getByText } = renderHighlightedFields(contextValue); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx index d47ab0c4b3c02f..48657615755b6b 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx @@ -95,7 +95,7 @@ const columns: Array> = [ export const HighlightedFields: FC = () => { const { dataFormattedForFieldBrowser, scopeId } = useRightPanelContext(); const { ruleId } = useBasicDataFromDetailsData(dataFormattedForFieldBrowser); - const { rule: maybeRule } = useRuleWithFallback(ruleId); + const { loading, error, rule: maybeRule } = useRuleWithFallback(ruleId); const highlightedFields = useHighlightedFields({ dataFormattedForFieldBrowser, @@ -106,10 +106,6 @@ export const HighlightedFields: FC = () => { [highlightedFields, scopeId] ); - if (items.length === 0) { - return null; - } - return ( @@ -124,7 +120,18 @@ export const HighlightedFields: FC = () => { - + + } + /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx index 8680120dfd2513..c5a9f7d7d324ae 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.test.tsx @@ -16,6 +16,7 @@ import { ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID, + ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID, } from './test_ids'; import { RightPanelContext } from '../context'; import { mockContextValue } from '../mocks/mock_context'; @@ -100,6 +101,33 @@ describe('', () => { }); }); + it('should render loading if loading for host details is true', () => { + mockUseHostDetails.mockReturnValue([true, { hostDetails: null }]); + mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: true }); + + const { getByTestId } = render( + + + + + + ); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID)).toBeInTheDocument(); + }); + + it('should render loading if loading for risk score is true', () => { + mockUseHostDetails.mockReturnValue([false, { hostDetails: null }]); + mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: true, loading: true }); + + const { getByTestId } = render( + + + + + + ); + expect(getByTestId(ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID)).toBeInTheDocument(); + }); describe('license is not valid', () => { it('should render os family and last seen', () => { mockUseHostDetails.mockReturnValue([false, { hostDetails: hostData }]); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx index 60d045006ac496..36f1bec0a8f5be 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx @@ -14,9 +14,11 @@ import { useEuiTheme, useEuiFontSize, EuiIconTip, + EuiSkeletonText, } from '@elastic/eui'; import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; +import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { useRightPanelContext } from '../context'; @@ -35,7 +37,11 @@ import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useRiskScore } from '../../../explore/containers/risk_score'; import { useHostDetails } from '../../../explore/hosts/containers/hosts/details'; -import * as i18n from '../../../overview/components/host_overview/translations'; +import { + FAMILY, + LAST_SEEN, + HOST_RISK_CLASSIFICATION, +} from '../../../overview/components/host_overview/translations'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { ENTITIES_HOST_OVERVIEW_TEST_ID, @@ -43,6 +49,7 @@ import { ENTITIES_HOST_OVERVIEW_LAST_SEEN_TEST_ID, ENTITIES_HOST_OVERVIEW_RISK_LEVEL_TEST_ID, ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, + ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID, TECHNICAL_PREVIEW_ICON_TEST_ID, } from './test_ids'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; @@ -91,14 +98,18 @@ export const HostEntityOverview: React.FC = ({ hostName [hostName] ); - const { data: hostRisk, isAuthorized } = useRiskScore({ + const { + data: hostRisk, + isAuthorized, + loading: isRiskScoreLoading, + } = useRiskScore({ filterQuery, riskEntity: RiskScoreEntity.host, skip: hostName == null, timerange, }); - const [_, { hostDetails }] = useHostDetails({ + const [isHostDetailsLoading, { hostDetails }] = useHostDetails({ hostName, indexNames: selectedPatterns, startDate: from, @@ -108,7 +119,7 @@ export const HostEntityOverview: React.FC = ({ hostName const hostOSFamily: DescriptionList[] = useMemo( () => [ { - title: i18n.FAMILY, + title: FAMILY, description: ( = ({ hostName const hostLastSeen: DescriptionList[] = useMemo( () => [ { - title: i18n.LAST_SEEN, + title: LAST_SEEN, description: ( = ({ hostName { title: ( <> - {i18n.HOST_RISK_CLASSIFICATION} + {HOST_RISK_CLASSIFICATION} = ({ hostName - - - - - - - {isAuthorized ? ( - - ) : ( + {isRiskScoreLoading || isHostDetailsLoading ? ( + + ) : ( + + + - )} - - - + + + {isAuthorized ? ( + + ) : ( + + )} + + + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx index 0dae715262fcc5..1dd3af16ff4159 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx @@ -13,7 +13,6 @@ import { RightPanelContext } from '../context'; import { INVESTIGATION_GUIDE_BUTTON_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID, - INVESTIGATION_GUIDE_NO_DATA_TEST_ID, INVESTIGATION_GUIDE_TEST_ID, } from './test_ids'; import { mockContextValue } from '../mocks/mock_context'; @@ -24,6 +23,8 @@ import { LeftPanelInvestigationTab, LeftPanelKey } from '../../left'; jest.mock('../../shared/hooks/use_investigation_guide'); +const NO_DATA_MESSAGE = 'Investigation guideThere’s no investigation guide for this rule.'; + const renderInvestigationGuide = () => render( @@ -51,7 +52,7 @@ describe('', () => { 'Show investigation guide' ); expect(queryByTestId(INVESTIGATION_GUIDE_LOADING_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).not.toHaveTextContent(NO_DATA_MESSAGE); }); it('should render loading', () => { @@ -59,10 +60,10 @@ describe('', () => { loading: true, }); const { getByTestId, queryByTestId } = renderInvestigationGuide(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(INVESTIGATION_GUIDE_LOADING_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(INVESTIGATION_GUIDE_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).not.toHaveTextContent(NO_DATA_MESSAGE); }); it('should render no data message when there is no ruleId', () => { @@ -70,12 +71,9 @@ describe('', () => { basicAlertData: {}, ruleNote: 'test note', }); - const { getByTestId, queryByTestId } = renderInvestigationGuide(); + const { queryByTestId, getByTestId } = renderInvestigationGuide(); expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( - 'There’s no investigation guide for this rule.' - ); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); it('should render no data message when there is no rule note', () => { @@ -85,10 +83,7 @@ describe('', () => { }); const { getByTestId, queryByTestId } = renderInvestigationGuide(); expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( - 'There’s no investigation guide for this rule.' - ); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); it('should render no data message when useInvestigationGuide errors out', () => { @@ -97,8 +92,9 @@ describe('', () => { error: true, }); - const { getByTestId } = renderInvestigationGuide(); - expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + const { queryByTestId, getByTestId } = renderInvestigationGuide(); + expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent(NO_DATA_MESSAGE); }); it('should navigate to investigation guide when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx index 05642d5425cc1b..d00310b360c261 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React, { useCallback } from 'react'; -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiTitle } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSkeletonText } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -15,7 +15,6 @@ import { LeftPanelKey, LeftPanelInvestigationTab } from '../../left'; import { INVESTIGATION_GUIDE_BUTTON_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID, - INVESTIGATION_GUIDE_NO_DATA_TEST_ID, INVESTIGATION_GUIDE_TEST_ID, } from './test_ids'; @@ -45,22 +44,9 @@ export const InvestigationGuide: React.FC = () => { }); }, [eventId, indexName, openLeftPanel, scopeId]); - if (loading) { - return ( - - - - - - ); - } - return ( - - + +
{
- - {!error && basicAlertData.ruleId && ruleNote ? ( + {loading ? ( + + ) : !error && basicAlertData.ruleId && ruleNote ? ( + { defaultMessage="Show investigation guide" /> - ) : ( -

- -

- )} -
+
+ ) : ( + + )}
); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/mitre_attack.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/mitre_attack.tsx index a4c02e2c3d2922..7eaf175cc0e5cd 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/mitre_attack.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/mitre_attack.tsx @@ -17,6 +17,7 @@ export const MitreAttack: FC = () => { const threatDetails = useMemo(() => getMitreComponentParts(searchHit), [searchHit]); if (!threatDetails || !threatDetails[0]) { + // Do not render empty message on MITRE attack because other frameworks could be used return null; } diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx index 0f4d37ab01eb43..e8fc55e66288ac 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx @@ -9,7 +9,7 @@ import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { render } from '@testing-library/react'; import { TestProviders } from '../../../common/mock'; import { RightPanelContext } from '../context'; -import { PREVALENCE_NO_DATA_TEST_ID, PREVALENCE_TEST_ID } from './test_ids'; +import { PREVALENCE_TEST_ID } from './test_ids'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import React from 'react'; import { PrevalenceOverview } from './prevalence_overview'; @@ -31,6 +31,8 @@ const TITLE_LINK_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(PREVALENCE const TITLE_ICON_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID(PREVALENCE_TEST_ID); const TITLE_TEXT_TEST_ID = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(PREVALENCE_TEST_ID); +const NO_DATA_MESSAGE = 'No prevalence data available.'; + const flyoutContextValue = { openLeftPanel: jest.fn(), } as unknown as ExpandableFlyoutContext; @@ -69,10 +71,10 @@ describe('', () => { data: [], }); - const { getByTestId, queryByTestId } = renderPrevalenceOverview(); + const { getByTestId, queryByText } = renderPrevalenceOverview(); expect(getByTestId(EXPANDABLE_PANEL_LOADING_TEST_ID(PREVALENCE_TEST_ID))).toBeInTheDocument(); - expect(queryByTestId(PREVALENCE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should render no-data message', () => { @@ -82,12 +84,8 @@ describe('', () => { data: [], }); - const { getByTestId } = renderPrevalenceOverview(); - - expect(getByTestId(PREVALENCE_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(PREVALENCE_NO_DATA_TEST_ID)).toHaveTextContent( - 'No prevalence data available.' - ); + const { getByText } = renderPrevalenceOverview(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should render only data with prevalence less than 10%', () => { @@ -116,7 +114,7 @@ describe('', () => { ], }); - const { queryByTestId, getByTestId } = renderPrevalenceOverview(); + const { queryByTestId, getByTestId, queryByText } = renderPrevalenceOverview(); expect(getByTestId(TITLE_LINK_TEST_ID)).toHaveTextContent('Prevalence'); @@ -131,7 +129,7 @@ describe('', () => { expect(queryByTestId(iconDataTestSubj2)).not.toBeInTheDocument(); expect(queryByTestId(valueDataTestSubj2)).not.toBeInTheDocument(); - expect(queryByTestId(PREVALENCE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); it('should navigate to left section Insights tab when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx index 36bb9c7c5b1690..233057a7245d94 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx @@ -12,7 +12,7 @@ import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; -import { PREVALENCE_NO_DATA_TEST_ID, PREVALENCE_TEST_ID } from './test_ids'; +import { PREVALENCE_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; @@ -107,12 +107,10 @@ export const PrevalenceOverview: FC = () => { /> )) ) : ( -

- -

+ )}
diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx index 200f4cf0536a01..f407c33a1e2106 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx @@ -8,11 +8,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import { - REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, - REASON_DETAILS_TEST_ID, - REASON_TITLE_TEST_ID, -} from './test_ids'; +import { REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, REASON_TITLE_TEST_ID } from './test_ids'; import { Reason } from './reason'; import { RightPanelContext } from '../context'; import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; @@ -43,6 +39,8 @@ const renderReason = (panelContext: RightPanelContext = panelContextValue) =>
); +const NO_DATA_MESSAGE = "There's no source event information for this alert."; + describe('', () => { it('should render the component for alert', () => { const { getByTestId } = renderReason(); @@ -73,9 +71,9 @@ describe('', () => { getFieldsData: () => {}, } as unknown as RightPanelContext; - const { getByTestId } = renderReason(panelContext); + const { getByText } = renderReason(panelContext); - expect(getByTestId(REASON_DETAILS_TEST_ID)).toBeEmptyDOMElement(); + expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); it('should open preview panel when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx index 2b44be75453a25..0d022f3a0735e5 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx @@ -69,6 +69,7 @@ export const Reason: FC = () => { defaultMessage: 'Show full reason', } )} + disabled={!alertReason} > { ), - [openRulePreview] + [alertReason, openRulePreview] + ); + + const alertReasonText = alertReason ? ( + alertReason + ) : ( + ); return ( @@ -108,7 +118,9 @@ export const Reason: FC = () => { - {alertReason} + + {isAlert ? alertReasonText : '-'} + ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx index dc572207cd6023..ef0d52cead5fbf 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx @@ -12,11 +12,7 @@ import { RightPanelContext } from '../context'; import { SessionPreviewContainer } from './session_preview_container'; import { useSessionPreview } from '../hooks/use_session_preview'; import { useLicense } from '../../../common/hooks/use_license'; -import { - SESSION_PREVIEW_NO_DATA_TEST_ID, - SESSION_PREVIEW_TEST_ID, - SESSION_PREVIEW_UPSELL_TEST_ID, -} from './test_ids'; +import { SESSION_PREVIEW_TEST_ID } from './test_ids'; import { EXPANDABLE_PANEL_CONTENT_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, @@ -29,6 +25,11 @@ import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; jest.mock('../hooks/use_session_preview'); jest.mock('../../../common/hooks/use_license'); +const NO_DATA_MESSAGE = + 'You can only view Linux session details if you’ve enabled the Include session data setting in your Elastic Defend integration policy. Refer to Enable Session View dataExternal link(opens in a new tab or window) for more information.'; + +const UPSELL_TEXT = 'This feature requires an Enterprise subscription'; + const panelContextValue = { getFieldsData: mockGetFieldsData, } as unknown as RightPanelContext; @@ -57,14 +58,13 @@ describe('SessionPreviewContainer', () => { (useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig); (useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true }); - const { getByTestId, queryByTestId } = renderSessionPreview(); + const { getByTestId } = renderSessionPreview(); expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); + expect( screen.queryByTestId(EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).not.toBeInTheDocument(); @@ -77,6 +77,12 @@ describe('SessionPreviewContainer', () => { expect( screen.queryByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).not.toBeInTheDocument(); + expect( + screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toHaveTextContent(NO_DATA_MESSAGE); + expect( + screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toHaveTextContent(UPSELL_TEXT); }); it('should render error message and text in header if no sessionConfig', () => { @@ -84,32 +90,35 @@ describe('SessionPreviewContainer', () => { (useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => true }); const { getByTestId, queryByTestId } = renderSessionPreview(); - - expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).toHaveTextContent( - 'You can only view Linux session details if you’ve enabled the Include session data setting in your Elastic Defend integration policy. Refer to Enable Session View dataExternal link(opens in a new tab or window) for more information.' - ); - expect(queryByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); + expect( + screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).toHaveTextContent(NO_DATA_MESSAGE); + + expect( + screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toHaveTextContent(UPSELL_TEXT); + expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); }); - it('should render error message and text in header if no correct license', () => { + it('should render upsell message in header if no correct license', () => { (useSessionPreview as jest.Mock).mockReturnValue(sessionViewConfig); (useLicense as jest.Mock).mockReturnValue({ isEnterprise: () => false }); const { getByTestId, queryByTestId } = renderSessionPreview(); - expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).toHaveTextContent( - 'This feature requires an Enterprise subscription' - ); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); + expect( + screen.getByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).toHaveTextContent(UPSELL_TEXT); + + expect( + screen.queryByTestId(EXPANDABLE_PANEL_CONTENT_TEST_ID(SESSION_PREVIEW_TEST_ID)) + ).not.toHaveTextContent(NO_DATA_MESSAGE); + expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx index 3fc3905ca6da97..f88d9d3f31a2c9 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx @@ -18,11 +18,7 @@ import { useInvestigateInTimeline } from '../../../detections/components/alerts_ import { useRightPanelContext } from '../context'; import { ALERTS_ACTIONS } from '../../../common/lib/apm/user_actions'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; -import { - SESSION_PREVIEW_NO_DATA_TEST_ID, - SESSION_PREVIEW_TEST_ID, - SESSION_PREVIEW_UPSELL_TEST_ID, -} from './test_ids'; +import { SESSION_PREVIEW_TEST_ID } from './test_ids'; import { useStartTransaction } from '../../../common/lib/apm/use_start_transaction'; import { setActiveTabTimeline } from '../../../timelines/store/timeline/actions'; import { getScopedActions } from '../../../helpers'; @@ -70,54 +66,50 @@ export const SessionPreviewContainer: FC = () => { const { euiTheme } = useEuiTheme(); const noSessionMessage = !isEnterprisePlus ? ( -
- - - - ), - }} - /> -
+ + + + ), + }} + /> ) : !sessionViewConfig ? ( -
- - - - ), - link: ( - - - - ), - }} - /> -
+ + + + ), + link: ( + + + + ), + }} + /> ) : null; return ( diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts index 8d1b13c12c1467..acff67542b0f4c 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts @@ -28,14 +28,17 @@ export const CHAT_BUTTON_TEST_ID = 'newChatById' as const; export const ABOUT_SECTION_TEST_ID = `${PREFIX}AboutSection` as const; export const ABOUT_SECTION_HEADER_TEST_ID = ABOUT_SECTION_TEST_ID + HEADER_TEST_ID; export const ABOUT_SECTION_CONTENT_TEST_ID = ABOUT_SECTION_TEST_ID + CONTENT_TEST_ID; + export const RULE_SUMMARY_BUTTON_TEST_ID = `${PREFIX}RuleSummaryButton` as const; const DESCRIPTION_TEST_ID = `${PREFIX}Description` as const; export const DESCRIPTION_TITLE_TEST_ID = `${DESCRIPTION_TEST_ID}Title` as const; export const DESCRIPTION_DETAILS_TEST_ID = `${DESCRIPTION_TEST_ID}Details` as const; + const REASON_TEST_ID = `${PREFIX}Reason` as const; export const REASON_TITLE_TEST_ID = `${REASON_TEST_ID}Title` as const; export const REASON_DETAILS_TEST_ID = `${REASON_TEST_ID}Details` as const; export const REASON_DETAILS_PREVIEW_BUTTON_TEST_ID = `${REASON_TEST_ID}PreviewButton` as const; + const MITRE_ATTACK_TEST_ID = `${PREFIX}MitreAttack` as const; export const MITRE_ATTACK_TITLE_TEST_ID = `${MITRE_ATTACK_TEST_ID}Title` as const; export const MITRE_ATTACK_DETAILS_TEST_ID = `${MITRE_ATTACK_TEST_ID}Details` as const; @@ -46,10 +49,11 @@ export const INVESTIGATION_SECTION_TEST_ID = `${PREFIX}InvestigationSection` as export const INVESTIGATION_SECTION_HEADER_TEST_ID = INVESTIGATION_SECTION_TEST_ID + HEADER_TEST_ID; export const INVESTIGATION_SECTION_CONTENT_TEST_ID = INVESTIGATION_SECTION_TEST_ID + CONTENT_TEST_ID; + export const INVESTIGATION_GUIDE_TEST_ID = `${PREFIX}InvestigationGuide` as const; export const INVESTIGATION_GUIDE_BUTTON_TEST_ID = `${INVESTIGATION_GUIDE_TEST_ID}Button` as const; export const INVESTIGATION_GUIDE_LOADING_TEST_ID = `${INVESTIGATION_GUIDE_TEST_ID}Loading` as const; -export const INVESTIGATION_GUIDE_NO_DATA_TEST_ID = `${INVESTIGATION_GUIDE_TEST_ID}NoData` as const; + const HIGHLIGHTED_FIELDS_TEST_ID = `${PREFIX}HighlightedFields` as const; export const HIGHLIGHTED_FIELDS_TITLE_TEST_ID = `${HIGHLIGHTED_FIELDS_TEST_ID}Title` as const; export const HIGHLIGHTED_FIELDS_DETAILS_TEST_ID = `${HIGHLIGHTED_FIELDS_TEST_ID}Details` as const; @@ -75,8 +79,10 @@ export const SUMMARY_ROW_VALUE_TEST_ID = (dataTestSubj: string) => `${dataTestSu /* Entities */ export const INSIGHTS_ENTITIES_TEST_ID = `${PREFIX}InsightsEntities` as const; -export const INSIGHTS_ENTITIES_NO_DATA_TEST_ID = `${INSIGHTS_ENTITIES_TEST_ID}NoData` as const; + export const ENTITIES_USER_OVERVIEW_TEST_ID = `${INSIGHTS_ENTITIES_TEST_ID}UserOverview` as const; +export const ENTITIES_USER_OVERVIEW_LOADING_TEST_ID = + `${ENTITIES_USER_OVERVIEW_TEST_ID}Loading` as const; export const ENTITIES_USER_OVERVIEW_LINK_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}Link` as const; export const ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}Domain` as const; @@ -84,7 +90,10 @@ export const ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}LastSeen` as const; export const ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID = `${ENTITIES_USER_OVERVIEW_TEST_ID}RiskLevel` as const; + export const ENTITIES_HOST_OVERVIEW_TEST_ID = `${INSIGHTS_ENTITIES_TEST_ID}HostOverview` as const; +export const ENTITIES_HOST_OVERVIEW_LOADING_TEST_ID = + `${ENTITIES_HOST_OVERVIEW_TEST_ID}Loading` as const; export const ENTITIES_HOST_OVERVIEW_LINK_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}Link` as const; export const ENTITIES_HOST_OVERVIEW_OS_FAMILY_TEST_ID = `${ENTITIES_HOST_OVERVIEW_TEST_ID}OsFamily` as const; @@ -102,7 +111,6 @@ export const INSIGHTS_THREAT_INTELLIGENCE_TEST_ID = `${PREFIX}InsightsThreatInte /* Correlations */ export const CORRELATIONS_TEST_ID = `${PREFIX}Correlations` as const; -export const CORRELATIONS_NO_DATA_TEST_ID = `${CORRELATIONS_TEST_ID}NoData` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID = `${CORRELATIONS_TEST_ID}SuppressedAlerts` as const; export const CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID = @@ -118,7 +126,6 @@ export const CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID = /* Insights Prevalence */ export const PREVALENCE_TEST_ID = `${PREFIX}InsightsPrevalence` as const; -export const PREVALENCE_NO_DATA_TEST_ID = `${PREVALENCE_TEST_ID}NoData` as const; /* Visualizations section */ @@ -127,10 +134,10 @@ export const VISUALIZATIONS_SECTION_TEST_ID = `${VISUALIZATIONS_TEST_ID}Title` a export const VISUALIZATIONS_SECTION_HEADER_TEST_ID = `${VISUALIZATIONS_TEST_ID}TitleHeader` as const; export const ANALYZER_PREVIEW_TEST_ID = `${PREFIX}AnalyzerPreview` as const; -export const ANALYZER_PREVIEW_NO_DATA_TEST_ID = `${ANALYZER_PREVIEW_TEST_ID}NoData` as const; +export const ANALYZER_PREVIEW_LOADING_TEST_ID = `${ANALYZER_PREVIEW_TEST_ID}Loading` as const; + export const SESSION_PREVIEW_TEST_ID = `${PREFIX}SessionPreview` as const; export const SESSION_PREVIEW_UPSELL_TEST_ID = `${SESSION_PREVIEW_TEST_ID}UpSell` as const; -export const SESSION_PREVIEW_NO_DATA_TEST_ID = `${SESSION_PREVIEW_TEST_ID}NoData` as const; /* Response section */ diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx index a111e5469e614b..4b0b5816f30146 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx @@ -134,9 +134,9 @@ describe('', () => { loading: true, }); - const { getAllByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - expect(getAllByTestId(LOADING_TEST_ID)).toHaveLength(2); + expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); it('should navigate to left section Insights tab when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx index 7fbcd048a1197e..9b5ad192ec3713 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx @@ -67,6 +67,7 @@ export const ThreatIntelligenceOverview: FC = () => { iconType: 'arrowStart', }} data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} + content={{ loading }} > { data-test-subj={`${INSIGHTS_THREAT_INTELLIGENCE_TEST_ID}Container`} > { data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} /> ', () => { expect(getByTestId(ENTITIES_USER_OVERVIEW_LAST_SEEN_TEST_ID)).toHaveTextContent('—'); }); + it('should render loading if user details returns loading as true', () => { + mockUseUserDetails.mockReturnValue([true, { userDetails: null }]); + mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: true }); + + const { getByTestId, queryByTestId } = render( + + + + + + ); + expect(getByTestId(ENTITIES_USER_OVERVIEW_LOADING_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).not.toBeInTheDocument(); + }); + + it('should render loading if risk score returns loading as true', () => { + mockUseUserDetails.mockReturnValue([false, { userDetails: null }]); + mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: true, loading: true }); + + const { getByTestId, queryByTestId } = render( + + + + + + ); + expect(getByTestId(ENTITIES_USER_OVERVIEW_LOADING_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID)).not.toBeInTheDocument(); + }); + it('should navigate to left panel entities tab when clicking on title', () => { mockUseUserDetails.mockReturnValue([false, { userDetails: userData }]); mockUseRiskScore.mockReturnValue({ data: riskLevel, isAuthorized: true }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx index 941a5c299ffbe6..e905607bfa740f 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx @@ -14,9 +14,11 @@ import { useEuiTheme, useEuiFontSize, EuiIconTip, + EuiSkeletonText, } from '@elastic/eui'; import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; +import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; @@ -36,7 +38,11 @@ import { RiskScore } from '../../../explore/components/risk_score/severity/commo import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useRiskScore } from '../../../explore/containers/risk_score'; -import * as i18n from '../../../overview/components/user_overview/translations'; +import { + USER_DOMAIN, + LAST_SEEN, + USER_RISK_CLASSIFICATION, +} from '../../../overview/components/user_overview/translations'; import { ENTITIES_USER_OVERVIEW_TEST_ID, ENTITIES_USER_OVERVIEW_DOMAIN_TEST_ID, @@ -44,6 +50,7 @@ import { ENTITIES_USER_OVERVIEW_RISK_LEVEL_TEST_ID, ENTITIES_USER_OVERVIEW_LINK_TEST_ID, TECHNICAL_PREVIEW_ICON_TEST_ID, + ENTITIES_USER_OVERVIEW_LOADING_TEST_ID, } from './test_ids'; import { useObservedUserDetails } from '../../../explore/users/containers/users/observed_details'; @@ -90,14 +97,18 @@ export const UserEntityOverview: React.FC = ({ userName () => (userName ? buildUserNamesFilter([userName]) : undefined), [userName] ); - const [_, { userDetails }] = useObservedUserDetails({ + const [isUserDetailsLoading, { userDetails }] = useObservedUserDetails({ endDate: to, userName, indexNames: selectedPatterns, startDate: from, }); - const { data: userRisk, isAuthorized } = useRiskScore({ + const { + data: userRisk, + isAuthorized, + loading: isRiskScoreLoading, + } = useRiskScore({ filterQuery, riskEntity: RiskScoreEntity.user, timerange, @@ -106,7 +117,7 @@ export const UserEntityOverview: React.FC = ({ userName const userDomain: DescriptionList[] = useMemo( () => [ { - title: i18n.USER_DOMAIN, + title: USER_DOMAIN, description: ( = ({ userName const userLastSeen: DescriptionList[] = useMemo( () => [ { - title: i18n.LAST_SEEN, + title: LAST_SEEN, description: ( = ({ userName { title: ( <> - {i18n.USER_RISK_CLASSIFICATION} + {USER_RISK_CLASSIFICATION} = ({ userName - - - - - - {isAuthorized ? ( - - ) : ( + {isUserDetailsLoading || isRiskScoreLoading ? ( + + ) : ( + + - )} - - + + + {isAuthorized ? ( + + ) : ( + + )} + + + )} ); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx index 3e273d7d126f33..208aa52cfeeca2 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx @@ -16,13 +16,13 @@ import { EuiLink, EuiTitle, EuiText, - EuiLoadingSpinner, useEuiTheme, EuiToolTip, + EuiSkeletonText, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import type { IconType } from '@elastic/eui'; import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; export interface ExpandablePanelPanelProps { header: { @@ -197,11 +197,13 @@ export const ExpandablePanel: React.FC = ({ }, [children, expandable, toggleStatus]); const content = loading ? ( - - - - - + ) : error ? null : ( children ); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx index e7889d30526c5c..d55e85b3e978b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx @@ -15,4 +15,10 @@ describe('', () => { const { getByTestId } = render(); expect(getByTestId(FLYOUT_LOADING_TEST_ID)).toBeInTheDocument(); }); + + it('should render loading when data test subject is passed', () => { + const { getByTestId, queryByTestId } = render(); + expect(getByTestId('test-id')).toBeInTheDocument(); + expect(queryByTestId(FLYOUT_LOADING_TEST_ID)).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx index e1186c6257efde..03ecb298c3d181 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx @@ -10,18 +10,25 @@ import { EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/react'; import { FLYOUT_LOADING_TEST_ID } from '../test_ids'; +interface FlyoutLoadingProps { + /** + Data test subject string for testing + */ + ['data-test-subj']?: string; +} + /** * Use this when you need to show a loading state in the flyout */ -export const FlyoutLoading: React.VFC = () => ( +export const FlyoutLoading: React.FC = ({ + 'data-test-subj': dataTestSubj = FLYOUT_LOADING_TEST_ID, +}) => ( - + ); - -FlyoutLoading.displayName = 'FlyoutLoading'; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts index a669d4f5f7a7e4..4636b96beaa04b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_left_panel_session_view_tab.cy.ts @@ -5,10 +5,7 @@ * 2.0. */ -import { - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON, - DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_ERROR, -} from '../../../../screens/expandable_flyout/alert_details_left_panel_session_view_tab'; +import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON } from '../../../../screens/expandable_flyout/alert_details_left_panel_session_view_tab'; import { DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB, DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_BUTTON_GROUP, @@ -48,12 +45,6 @@ describe.skip( cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON) .should('be.visible') .and('have.text', 'Session View'); - - // TODO ideally we would have a test for the session view component instead - cy.get(DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_ERROR) - .should('be.visible') - .and('contain.text', 'Unable to display session view') - .and('contain.text', 'There was an error displaying session view'); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts index 9761e04aadc867..a2aad15ff504bc 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_response_tab.ts @@ -6,10 +6,15 @@ */ import { RESPONSE_TAB_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/test_ids'; -import { RESPONSE_NO_DATA_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; +import { + RESPONSE_DETAILS_TEST_ID, + RESPONSE_NO_DATA_TEST_ID, +} from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_RESPONSE_TAB = getDataTestSubjectSelector(RESPONSE_TAB_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_RESPONSE_DETAILS = + getDataTestSubjectSelector(RESPONSE_DETAILS_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_RESPONSE_EMPTY = getDataTestSubjectSelector(RESPONSE_NO_DATA_TEST_ID); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts index d7e4f86d79c826..d50f645cf9359c 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/expandable_flyout/alert_details_left_panel_session_view_tab.ts @@ -6,12 +6,8 @@ */ import { VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/tabs/test_ids'; -import { SESSION_VIEW_ERROR_TEST_ID } from '@kbn/security-solution-plugin/public/flyout/left/components/test_ids'; import { getDataTestSubjectSelector } from '../../helpers/common'; export const DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_BUTTON = getDataTestSubjectSelector( VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID ); -export const DOCUMENT_DETAILS_FLYOUT_VISUALIZE_TAB_SESSION_VIEW_ERROR = getDataTestSubjectSelector( - SESSION_VIEW_ERROR_TEST_ID -); From af51e263339664f66331d9c00d388c084b69abed Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Wed, 27 Sep 2023 22:26:36 +0200 Subject: [PATCH 08/22] [Security Solution] expandable flyout - fix prevalence query not taking into account fields with multiple values (#166891) --- .../components/prevalence_details.test.tsx | 39 ++++++++++++++-- .../left/components/prevalence_details.tsx | 46 ++++++++++--------- .../components/prevalence_overview.test.tsx | 25 ++++++++-- .../right/components/prevalence_overview.tsx | 2 +- .../shared/hooks/use_prevalence.test.tsx | 2 +- .../flyout/shared/hooks/use_prevalence.ts | 7 ++- .../utils/highlighted_fields_helpers.test.ts | 6 +-- .../utils/highlighted_fields_helpers.ts | 2 +- 8 files changed, 87 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx index 9a1181fe006411..b8f09506ef46b5 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx @@ -79,7 +79,7 @@ describe('PrevalenceDetails', () => { data: [ { field: field1, - value: 'value1', + values: ['value1'], alertCount: 1, docCount: 1, hostPrevalence: 0.05, @@ -87,7 +87,7 @@ describe('PrevalenceDetails', () => { }, { field: field2, - value: 'value2', + values: ['value2'], alertCount: 1, docCount: 1, hostPrevalence: 0.5, @@ -124,7 +124,7 @@ describe('PrevalenceDetails', () => { data: [ { field: 'field1', - value: 'value1', + values: ['value1'], alertCount: 1000, docCount: 2000000, hostPrevalence: 0.05, @@ -154,6 +154,35 @@ describe('PrevalenceDetails', () => { ); }); + it('should render multiple values in value column', () => { + (usePrevalence as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [ + { + field: 'field1', + values: ['value1', 'value2'], + alertCount: 1000, + docCount: 2000000, + hostPrevalence: 0.05, + userPrevalence: 0.1, + }, + ], + }); + + const { getByTestId } = render( + + + + + + ); + + expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID)).toHaveTextContent('value1'); + expect(getByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID)).toHaveTextContent('value2'); + }); + it('should render the table with only basic columns if license is not platinum', () => { const field1 = 'field1'; const field2 = 'field2'; @@ -163,7 +192,7 @@ describe('PrevalenceDetails', () => { data: [ { field: field1, - value: 'value1', + values: ['value1'], alertCount: 1, docCount: 1, hostPrevalence: 0.05, @@ -171,7 +200,7 @@ describe('PrevalenceDetails', () => { }, { field: field2, - value: 'value2', + values: ['value2'], alertCount: 1, docCount: 1, hostPrevalence: 0.5, diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx index 9ddae380c91362..418e895dda3a2c 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx @@ -74,7 +74,7 @@ const columns: Array> = [ width: '20%', }, { - field: 'value', + field: 'values', name: ( > = [ /> ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, - render: (value: string) => {value}, + render: (values: string[]) => ( + + {values.map((value) => ( + + {value} + + ))} + + ), width: '20%', }, { @@ -113,9 +121,9 @@ const columns: Array> = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, render: (data: PrevalenceDetailsRow) => { - const dataProviders = [ - getDataProvider(data.field, `timeline-indicator-${data.field}-${data.value}`, data.value), - ]; + const dataProviders = data.values.map((value) => + getDataProvider(data.field, `timeline-indicator-${data.field}-${value}`, value) + ); return data.alertCount > 0 ? ( > = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, render: (data: PrevalenceDetailsRow) => { - const dataProviders = [ - { - ...getDataProvider( - data.field, - `timeline-indicator-${data.field}-${data.value}`, - data.value + const dataProviders = data.values.map((value) => ({ + ...getDataProvider(data.field, `timeline-indicator-${data.field}-${value}`, value), + and: [ + getDataProviderAnd( + 'event.kind', + `timeline-indicator-event.kind-not-signal`, + 'signal', + IS_OPERATOR, + true ), - and: [ - getDataProviderAnd( - 'event.kind', - `timeline-indicator-event.kind-not-signal`, - 'signal', - IS_OPERATOR, - true - ), - ], - }, - ]; + ], + })); return data.docCount > 0 ? ( ', () => { it('should render only data with prevalence less than 10%', () => { const field1 = 'field1'; const field2 = 'field2'; + const field3 = 'field3'; (usePrevalence as jest.Mock).mockReturnValue({ loading: false, error: false, data: [ { field: field1, - value: 'value1', + values: ['value1'], alertCount: 1, docCount: 1, hostPrevalence: 0.05, @@ -105,7 +106,15 @@ describe('', () => { }, { field: field2, - value: 'value2', + values: ['value2', 'value22'], + alertCount: 1, + docCount: 1, + hostPrevalence: 0.06, + userPrevalence: 0.2, + }, + { + field: field3, + values: ['value3'], alertCount: 1, docCount: 1, hostPrevalence: 0.5, @@ -126,8 +135,14 @@ describe('', () => { const iconDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Icon`; const valueDataTestSubj2 = `${PREVALENCE_TEST_ID}${field2}Value`; - expect(queryByTestId(iconDataTestSubj2)).not.toBeInTheDocument(); - expect(queryByTestId(valueDataTestSubj2)).not.toBeInTheDocument(); + expect(getByTestId(iconDataTestSubj2)).toBeInTheDocument(); + expect(getByTestId(valueDataTestSubj2)).toBeInTheDocument(); + expect(getByTestId(valueDataTestSubj2)).toHaveTextContent('field2, value2,value22 is uncommon'); + + const iconDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Icon`; + const valueDataTestSubj3 = `${PREVALENCE_TEST_ID}${field3}Value`; + expect(queryByTestId(iconDataTestSubj3)).not.toBeInTheDocument(); + expect(queryByTestId(valueDataTestSubj3)).not.toBeInTheDocument(); expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); }); @@ -139,7 +154,7 @@ describe('', () => { data: [ { field: 'field1', - value: 'value1', + values: ['value1'], alertCount: 1, docCount: 1, hostPrevalence: 0.05, diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx index 233057a7245d94..5aad186b24c0c8 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx @@ -99,7 +99,7 @@ export const PrevalenceOverview: FC = () => { } data-test-subj={`${PREVALENCE_TEST_ID}${d.field}`} diff --git a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.test.tsx index 3f7d73923b8fa6..a9c12adfc84ca6 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.test.tsx @@ -124,7 +124,7 @@ describe('usePrevalence', () => { expect(hookResult.result.current.data).toEqual([ { field: 'host.name', - value: 'host-1', + values: ['host-1'], alertCount: 1, docCount: 1, hostPrevalence: 0.1, diff --git a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.ts b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.ts index a78295139d7244..8811c91a0b34d2 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_prevalence.ts @@ -6,7 +6,6 @@ */ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; -import { isArray } from 'lodash/fp'; import { useMemo } from 'react'; import { useHighlightedFields } from './use_highlighted_fields'; import { convertHighlightedFieldsToPrevalenceFilters } from '../utils/highlighted_fields_helpers'; @@ -24,7 +23,7 @@ import { EventKind } from '../constants/event_kinds'; export interface PrevalenceData { field: string; - value: string; + values: string[]; alertCount: number; docCount: number; hostPrevalence: number; @@ -91,7 +90,7 @@ export const usePrevalence = ({ const fieldNames = Object.keys(data.aggregations[FIELD_NAMES_AGG_KEY].buckets); fieldNames.forEach((fieldName: string) => { - const fieldValue = highlightedFields[fieldName].values; + const fieldValues = highlightedFields[fieldName].values; // retrieves the number of signals for the current field/value pair const alertCount = @@ -131,7 +130,7 @@ export const usePrevalence = ({ items.push({ field: fieldName, - value: isArray(fieldValue) ? fieldValue[0] : fieldValue, + values: fieldValues, alertCount, docCount, hostPrevalence, diff --git a/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.test.ts b/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.test.ts index ec92745455e213..3992966878192b 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.test.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.test.ts @@ -58,12 +58,12 @@ describe('convertHighlightedFieldsToPrevalenceFilters', () => { values: ['host-1'], }, 'user.name': { - values: ['user-1'], + values: ['user-1', 'user-2'], }, }; expect(convertHighlightedFieldsToPrevalenceFilters(highlightedFields)).toEqual({ - 'host.name': { match: { 'host.name': 'host-1' } }, - 'user.name': { match: { 'user.name': 'user-1' } }, + 'host.name': { terms: { 'host.name': ['host-1'] } }, + 'user.name': { terms: { 'user.name': ['user-1', 'user-2'] } }, }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.ts b/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.ts index 094187b570251b..d41ff1b75f28a5 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/utils/highlighted_fields_helpers.ts @@ -48,7 +48,7 @@ export const convertHighlightedFieldsToPrevalenceFilters = ( return { ...acc, - [curr]: { match: { [curr]: Array.isArray(values) ? values[0] : values } }, + [curr]: { terms: { [curr]: values } }, }; }, []) as unknown as Record; }; From 9fba1e3f243c3ba3f802011a5c89a5a930268cb8 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 27 Sep 2023 15:36:44 -0500 Subject: [PATCH 09/22] fix type import --- .../public/application/lib/snapshot_list_params.ts | 2 +- .../home/snapshot_list/components/snapshot_search_bar.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts b/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts index 20276ae58b8e41..352eb658dd0238 100644 --- a/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts +++ b/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts @@ -6,7 +6,7 @@ */ import { Direction, Query } from '@elastic/eui'; -import { SchemaType } from '@elastic/eui/src/components/search_bar/search_box'; +import { SchemaType } from '@elastic/eui/src/components/search_bar/search_bar'; export type SortField = | 'snapshot' diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_search_bar.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_search_bar.tsx index 4b5c5af331832f..c2972a4c0a4d12 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_search_bar.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_search_bar.tsx @@ -11,7 +11,7 @@ import useDebounce from 'react-use/lib/useDebounce'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SearchFilterConfig } from '@elastic/eui/src/components/search_bar/search_filters'; -import { SchemaType } from '@elastic/eui/src/components/search_bar/search_box'; +import { SchemaType } from '@elastic/eui/src/components/search_bar/search_bar'; import { EuiSearchBarOnChangeArgs } from '@elastic/eui/src/components/search_bar/search_bar'; import { EuiButton, EuiCallOut, EuiSearchBar, EuiSpacer, Query } from '@elastic/eui'; import { SnapshotDeleteProvider } from '../../../../components'; From 0c680d7783858172dfbabde6e0f18143c18a97a0 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 27 Sep 2023 14:22:46 -0700 Subject: [PATCH 10/22] Project Side Navigation: Use EuiCollapsibleNavBeta component (#164910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Closes https://github.com/elastic/kibana/issues/162507 Relates to https://github.com/elastic/kibana/issues/166545 ^ additional IA-related tasks - related to the alignment discussions - can be found here ## Work for next steps In this PR, some work items are being saved for a next PR: 1. _Only affects Search solution_: Navigation "group titles" do not create a breadcrumb item, as sub-items in the group are not hierarchically under the title. To address this, group titles may be going away from the design. https://github.com/elastic/kibana/issues/167323 2. _Only affects Observability solution_: Navigation accordions can not be collapsed and do not show arrow icons. To address this, in a later PR we will add internal state management for the open/closed state of each accordion. https://github.com/elastic/kibana/issues/167328 3. _Affects all solutions:_ The "collapsed" state of the side nav should show a docked view with icons-only. To address this, in later PRs we will bring Security solution into the unified nav components. 4. https://github.com/elastic/kibana/issues/167326 5. https://github.com/elastic/kibana/issues/167330 6. https://github.com/elastic/kibana/issues/167332 ### Recordings These videos show a before-and-after with the new UI. | project | old | new | |--|--|--| |observability| https://github.com/elastic/kibana/assets/908371/663765a3-4e4b-416e-b7d5-7d87eece83e8 | CleanShot 2023-09-22 at 14 20 48@2x | |search| https://github.com/elastic/kibana/assets/908371/f383773e-27a8-4485-8289-274d8231b960 | CleanShot 2023-09-22 at 14 18 43@2x | |security| https://github.com/elastic/kibana/assets/908371/481f4533-64e5-41db-bc8e-5012f82c188a | *will change to the new style after this PR and the flyout/panel support are completed | ### 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 - [ ] 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)) - [ ] 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: Sébastien Loix --- .../src/ui/project/app_menu.tsx | 1 - .../src/ui/project/header.test.tsx | 31 +- .../src/ui/project/header.tsx | 50 +-- .../src/ui/project/navigation.tsx | 60 +--- .../src/project_navigation.ts | 15 +- .../analytics/default_navigation.ts | 19 +- .../devtools/default_navigation.ts | 25 +- .../management/default_navigation.ts | 8 +- packages/default-nav/ml/default_navigation.ts | 14 +- .../chrome/navigation/mocks/src/storybook.ts | 4 +- .../shared-ux/chrome/navigation/src/styles.ts | 15 - .../default_navigation.test.tsx.snap | 289 ++++++---------- .../src/ui/components/group_as_link.tsx | 61 ---- .../src/ui/components/navigation.test.tsx | 205 ++++------- .../src/ui/components/navigation_group.tsx | 2 +- .../src/ui/components/navigation_item.tsx | 21 +- .../ui/components/navigation_section_ui.tsx | 116 +++---- .../src/ui/components/navigation_ui.tsx | 19 +- .../src/ui/components/recently_accessed.tsx | 54 ++- .../src/ui/default_navigation.test.tsx | 42 +-- .../navigation/src/ui/default_navigation.tsx | 29 +- .../src/ui/hooks/use_init_navnode.ts | 16 +- .../navigation/src/ui/navigation.stories.tsx | 325 +++++++++++------- .../chrome/navigation/src/ui/types.ts | 27 +- .../components/side_navigation/index.tsx | 236 +++++++------ .../serverless_search/public/layout/nav.tsx | 150 ++++---- .../page_objects/svl_common_navigation.ts | 24 +- .../test_suites/search/navigation.ts | 17 +- 28 files changed, 763 insertions(+), 1112 deletions(-) delete mode 100644 packages/shared-ux/chrome/navigation/src/styles.ts delete mode 100644 packages/shared-ux/chrome/navigation/src/ui/components/group_as_link.tsx diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/app_menu.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/app_menu.tsx index 0fb7a3f1bd94c8..22ff7c9415ba8e 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/app_menu.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/app_menu.tsx @@ -13,7 +13,6 @@ import React from 'react'; import { HeaderActionMenu } from '../header/header_action_menu'; interface AppMenuBarProps { - isOpen: boolean; headerActionMenuMounter: { mount: MountPoint | undefined }; } export const AppMenuBar = ({ headerActionMenuMounter }: AppMenuBarProps) => { diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx index 167b11629ce553..d4886d8180c476 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx @@ -9,7 +9,7 @@ import { EuiHeader } from '@elastic/eui'; import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; import { docLinksServiceMock } from '@kbn/core-doc-links-browser-mocks'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import * as Rx from 'rxjs'; import { ProjectHeader, Props as ProjectHeaderProps } from './header'; @@ -45,35 +45,10 @@ describe('Header', () => { ); - expect(await screen.findByTestId('toggleNavButton')).toBeVisible(); + expect(await screen.findByTestId('euiCollapsibleNavButton')).toBeVisible(); expect(await screen.findByText('Hello, world!')).toBeVisible(); }); - it('can collapse and uncollapse', async () => { - render( - - Hello, goodbye! - - ); - - expect(await screen.findByTestId('toggleNavButton')).toBeVisible(); - expect(await screen.findByText('Hello, goodbye!')).toBeVisible(); // title is shown - - const toggleNav = async () => { - fireEvent.click(await screen.findByTestId('toggleNavButton')); // click - - expect(await screen.findByText('Hello, goodbye!')).not.toBeVisible(); - - fireEvent.click(await screen.findByTestId('toggleNavButton')); // click again - - expect(await screen.findByText('Hello, goodbye!')).toBeVisible(); // title is shown - }; - - await toggleNav(); - await toggleNav(); - await toggleNav(); - }); - it('displays the link to projects', async () => { render( @@ -81,7 +56,7 @@ describe('Header', () => { ); - const projectsLink = await screen.getByTestId('projectsLink'); + const projectsLink = screen.getByTestId('projectsLink'); expect(projectsLink).toHaveAttribute('href', '/projects/'); expect(projectsLink).toHaveTextContent('My Project'); }); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index 1cbf8eaa9af0a6..8767c1f9c53f76 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -12,10 +12,7 @@ import { EuiHeaderLogo, EuiHeaderSection, EuiHeaderSectionItem, - EuiHeaderSectionItemButton, - EuiIcon, EuiLoadingSpinner, - htmlIdGenerator, useEuiTheme, EuiThemeComputed, } from '@elastic/eui'; @@ -35,8 +32,7 @@ import { MountPoint } from '@kbn/core-mount-utils-browser'; import { i18n } from '@kbn/i18n'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { Router } from '@kbn/shared-ux-router'; -import React, { createRef, useCallback, useState } from 'react'; -import useLocalStorage from 'react-use/lib/useLocalStorage'; +import React, { useCallback } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { debounceTime, Observable, of } from 'rxjs'; import { useHeaderActionMenuMounter } from '../header/header_action_menu'; @@ -66,13 +62,6 @@ const getHeaderCss = ({ size }: EuiThemeComputed) => ({ top: 2px; `, }, - nav: { - toggleNavButton: css` - border-right: 1px solid #d3dae6; - margin-left: -1px; - padding-right: ${size.xs}; - `, - }, projectName: { link: css` /* TODO: make header layout more flexible? */ @@ -123,7 +112,6 @@ export interface Props { prependBasePath: (url: string) => string; } -const LOCAL_STORAGE_IS_OPEN_KEY = 'PROJECT_NAVIGATION_OPEN' as const; const LOADING_DEBOUNCE_TIME = 80; type LogoProps = Pick & { @@ -186,9 +174,6 @@ export const ProjectHeader = ({ docLinks, ...observables }: Props) => { - const [navId] = useState(htmlIdGenerator()()); - const [isOpen, setIsOpen] = useLocalStorage(LOCAL_STORAGE_IS_OPEN_KEY, true); - const toggleCollapsibleNavRef = createRef void }>(); const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$); const projectsUrl = useObservable(observables.projectsUrl$); const projectName = useObservable(observables.projectName$); @@ -210,34 +195,9 @@ export const ProjectHeader = ({
- - - { - setIsOpen(false); - if (toggleCollapsibleNavRef.current) { - toggleCollapsibleNavRef.current.focus(); - } - }} - button={ - setIsOpen(!isOpen)} - aria-expanded={isOpen!} - aria-pressed={isOpen!} - aria-controls={navId} - ref={toggleCollapsibleNavRef} - > - - - } - > - {children} - - - + + {children} + {headerActionMenuMounter.mount && ( - + )} ); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx index 1d48a6eccfbb50..ae5c8c773e4491 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx @@ -6,55 +6,25 @@ * Side Public License, v 1. */ +import { EuiCollapsibleNavBeta } from '@elastic/eui'; import React from 'react'; -import { css } from '@emotion/react'; -import { EuiCollapsibleNav, EuiCollapsibleNavProps } from '@elastic/eui'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; -const SIZE_EXPANDED = 248; -const SIZE_COLLAPSED = 0; +const LOCAL_STORAGE_IS_COLLAPSED_KEY = 'PROJECT_NAVIGATION_COLLAPSED' as const; -export interface ProjectNavigationProps { - isOpen: boolean; - closeNav: () => void; - button: EuiCollapsibleNavProps['button']; -} - -export const ProjectNavigation: React.FC = ({ - children, - isOpen, - closeNav, - button, -}) => { - const collabsibleNavCSS = css` - border-inline-end-width: 1, - display: flex, - flex-direction: row, - `; - - const DOCKED_BREAKPOINT = 's' as const; - const isVisible = isOpen; +export const ProjectNavigation: React.FC = ({ children }) => { + const [isCollapsed, setIsCollapsed] = useLocalStorage(LOCAL_STORAGE_IS_COLLAPSED_KEY, false); + const onCollapseToggle = (nextIsCollapsed: boolean) => { + setIsCollapsed(nextIsCollapsed); + }; return ( - <> - { - /* must render the tree to initialize the navigation, even if it shouldn't be visible */ - !isOpen && - } - - {isOpen && children} - - + + {children} + ); }; diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index b2a0384e3a1a9f..2d35272e436794 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -5,8 +5,10 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ + import type { ComponentType } from 'react'; import type { Location } from 'history'; +import { EuiAccordionProps } from '@elastic/eui'; import type { AppId as DevToolsApp, DeepLinkId as DevToolsLink } from '@kbn/deeplinks-devtools'; import type { AppId as AnalyticsApp, @@ -68,6 +70,8 @@ export interface ChromeProjectNavigationNode { deepLink?: ChromeNavLink; /** Optional icon for the navigation node. Note: not all navigation depth will render the icon */ icon?: string; + /** Optional flag to indicate if the node must be treated as a group title */ + isGroupTitle?: boolean; /** Optional children of the navigation node */ children?: ChromeProjectNavigationNode[]; /** @@ -88,6 +92,8 @@ export interface ChromeProjectNavigationNode { * @default 'visible' */ breadcrumbStatus?: 'hidden' | 'visible'; + + accordionProps?: Partial; } /** @public */ @@ -139,7 +145,12 @@ export interface NodeDefinition< cloudLink?: CloudLinkId; /** Optional icon for the navigation node. Note: not all navigation depth will render the icon */ icon?: string; - /** Optional children of the navigation node */ + /** + * Optional flag to indicate if the node must be treated as a group title. + * Can not be used with `children` + */ + isGroupTitle?: boolean; + /** Optional children of the navigation node. Can not be used with `isGroupTitle` */ children?: NonEmptyArray>; /** * Use href for absolute links only. Internal links should use "link". @@ -155,6 +166,8 @@ export interface NodeDefinition< * @default 'visible' */ breadcrumbStatus?: 'hidden' | 'visible'; + + accordionProps?: Partial; } /** diff --git a/packages/default-nav/analytics/default_navigation.ts b/packages/default-nav/analytics/default_navigation.ts index a9c0c414936b5e..0ea0b5cd822f1d 100644 --- a/packages/default-nav/analytics/default_navigation.ts +++ b/packages/default-nav/analytics/default_navigation.ts @@ -21,18 +21,13 @@ export const defaultNavigation: AnalyticsNodeDefinition = { icon: 'stats', children: [ { - id: 'root', - children: [ - { - link: 'discover', - }, - { - link: 'dashboards', - }, - { - link: 'visualize', - }, - ], + link: 'discover', + }, + { + link: 'dashboards', + }, + { + link: 'visualize', }, ], }; diff --git a/packages/default-nav/devtools/default_navigation.ts b/packages/default-nav/devtools/default_navigation.ts index 3a2f8db48c5632..8235af8b602a55 100644 --- a/packages/default-nav/devtools/default_navigation.ts +++ b/packages/default-nav/devtools/default_navigation.ts @@ -21,21 +21,16 @@ export const defaultNavigation: DevToolsNodeDefinition = { icon: 'editorCodeBlock', children: [ { - id: 'root', - children: [ - { - link: 'dev_tools:console', - }, - { - link: 'dev_tools:searchprofiler', - }, - { - link: 'dev_tools:grokdebugger', - }, - { - link: 'dev_tools:painless_lab', - }, - ], + link: 'dev_tools:console', + }, + { + link: 'dev_tools:searchprofiler', + }, + { + link: 'dev_tools:grokdebugger', + }, + { + link: 'dev_tools:painless_lab', }, ], }; diff --git a/packages/default-nav/management/default_navigation.ts b/packages/default-nav/management/default_navigation.ts index afc889c9a1e1b3..180f9d74378f81 100644 --- a/packages/default-nav/management/default_navigation.ts +++ b/packages/default-nav/management/default_navigation.ts @@ -29,13 +29,7 @@ export const defaultNavigation: ManagementNodeDefinition = { icon: 'gear', children: [ { - id: 'root', - title: '', - children: [ - { - link: 'monitoring', - }, - ], + link: 'monitoring', }, { id: 'integration_management', diff --git a/packages/default-nav/ml/default_navigation.ts b/packages/default-nav/ml/default_navigation.ts index c0035f6f25db0e..97f53d6346653a 100644 --- a/packages/default-nav/ml/default_navigation.ts +++ b/packages/default-nav/ml/default_navigation.ts @@ -28,16 +28,10 @@ export const defaultNavigation: MlNodeDefinition = { icon: 'machineLearningApp', children: [ { - title: '', - id: 'root', - children: [ - { - link: 'ml:overview', - }, - { - link: 'ml:notifications', - }, - ], + link: 'ml:overview', + }, + { + link: 'ml:notifications', }, { title: i18n.translate('defaultNavigation.ml.anomalyDetection', { diff --git a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts index 28184ee086cc74..d8ed78c48e7a95 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts @@ -14,7 +14,7 @@ import { NavigationServices } from '../../types'; type Arguments = NavigationServices; export type Params = Pick< Arguments, - 'navIsOpen' | 'recentlyAccessed$' | 'navLinks$' | 'onProjectNavigationChange' + 'navIsOpen' | 'recentlyAccessed$' | 'activeNodes$' | 'navLinks$' | 'onProjectNavigationChange' >; export class StorybookMock extends AbstractStorybookMock<{}, NavigationServices> { @@ -43,7 +43,7 @@ export class StorybookMock extends AbstractStorybookMock<{}, NavigationServices> recentlyAccessed$: params.recentlyAccessed$ ?? new BehaviorSubject([]), navLinks$: params.navLinks$ ?? new BehaviorSubject([]), onProjectNavigationChange: params.onProjectNavigationChange ?? (() => undefined), - activeNodes$: new BehaviorSubject([]), + activeNodes$: params.activeNodes$ ?? new BehaviorSubject([]), cloudLinks: { billingAndSub: { title: 'Billing & Subscriptions', diff --git a/packages/shared-ux/chrome/navigation/src/styles.ts b/packages/shared-ux/chrome/navigation/src/styles.ts deleted file mode 100644 index 72db66e12f7bf1..00000000000000 --- a/packages/shared-ux/chrome/navigation/src/styles.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { css } from '@emotion/react'; - -export const navigationStyles = { - euiSideNavItems: css` - padding-left: 45px; - `, -}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap b/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap index d73d9c68385bc0..46ffd04af56d86 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap +++ b/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap @@ -14,7 +14,6 @@ Array [ "group1", "item1", ], - "renderItem": undefined, "title": "Item 1", }, Object { @@ -33,7 +32,6 @@ Array [ "group1", "item2", ], - "renderItem": undefined, "title": "Title from deeplink!", }, Object { @@ -52,7 +50,6 @@ Array [ "group1", "item3", ], - "renderItem": undefined, "title": "Deeplink title overriden", }, ], @@ -69,77 +66,58 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/discover", - "id": "discover", - "title": "Deeplink discover", - "url": "/mocked/discover", - }, - "href": undefined, - "id": "discover", - "isActive": false, - "path": Array [ - "rootNav:analytics", - "root", - "discover", - ], - "renderItem": undefined, - "title": "Deeplink discover", - }, - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/dashboards", - "id": "dashboards", - "title": "Deeplink dashboards", - "url": "/mocked/dashboards", - }, - "href": undefined, - "id": "dashboards", - "isActive": false, - "path": Array [ - "rootNav:analytics", - "root", - "dashboards", - ], - "renderItem": undefined, - "title": "Deeplink dashboards", - }, - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/visualize", - "id": "visualize", - "title": "Deeplink visualize", - "url": "/mocked/visualize", - }, - "href": undefined, - "id": "visualize", - "isActive": false, - "path": Array [ - "rootNav:analytics", - "root", - "visualize", - ], - "renderItem": undefined, - "title": "Deeplink visualize", - }, + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/discover", + "id": "discover", + "title": "Deeplink discover", + "url": "/mocked/discover", + }, + "href": undefined, + "id": "discover", + "isActive": false, + "path": Array [ + "rootNav:analytics", + "discover", ], - "deepLink": undefined, + "title": "Deeplink discover", + }, + Object { + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/dashboards", + "id": "dashboards", + "title": "Deeplink dashboards", + "url": "/mocked/dashboards", + }, "href": undefined, - "id": "root", + "id": "dashboards", "isActive": false, "path": Array [ "rootNav:analytics", - "root", + "dashboards", ], - "title": "", + "title": "Deeplink dashboards", + }, + Object { + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/visualize", + "id": "visualize", + "title": "Deeplink visualize", + "url": "/mocked/visualize", + }, + "href": undefined, + "id": "visualize", + "isActive": false, + "path": Array [ + "rootNav:analytics", + "visualize", + ], + "title": "Deeplink visualize", }, ], "deepLink": undefined, @@ -156,57 +134,40 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/ml:overview", - "id": "ml:overview", - "title": "Deeplink ml:overview", - "url": "/mocked/ml:overview", - }, - "href": undefined, - "id": "ml:overview", - "isActive": false, - "path": Array [ - "rootNav:ml", - "root", - "ml:overview", - ], - "renderItem": undefined, - "title": "Deeplink ml:overview", - }, - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/ml:notifications", - "id": "ml:notifications", - "title": "Deeplink ml:notifications", - "url": "/mocked/ml:notifications", - }, - "href": undefined, - "id": "ml:notifications", - "isActive": false, - "path": Array [ - "rootNav:ml", - "root", - "ml:notifications", - ], - "renderItem": undefined, - "title": "Deeplink ml:notifications", - }, + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/ml:overview", + "id": "ml:overview", + "title": "Deeplink ml:overview", + "url": "/mocked/ml:overview", + }, + "href": undefined, + "id": "ml:overview", + "isActive": false, + "path": Array [ + "rootNav:ml", + "ml:overview", ], - "deepLink": undefined, + "title": "Deeplink ml:overview", + }, + Object { + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/ml:notifications", + "id": "ml:notifications", + "title": "Deeplink ml:notifications", + "url": "/mocked/ml:notifications", + }, "href": undefined, - "id": "root", + "id": "ml:notifications", "isActive": false, "path": Array [ "rootNav:ml", - "root", + "ml:notifications", ], - "title": "", + "title": "Deeplink ml:notifications", }, Object { "children": Array [ @@ -227,7 +188,6 @@ Array [ "anomaly_detection", "ml:anomalyDetection", ], - "renderItem": undefined, "title": "Jobs", }, Object { @@ -247,7 +207,6 @@ Array [ "anomaly_detection", "ml:anomalyExplorer", ], - "renderItem": undefined, "title": "Deeplink ml:anomalyExplorer", }, Object { @@ -267,7 +226,6 @@ Array [ "anomaly_detection", "ml:singleMetricViewer", ], - "renderItem": undefined, "title": "Deeplink ml:singleMetricViewer", }, Object { @@ -287,7 +245,6 @@ Array [ "anomaly_detection", "ml:settings", ], - "renderItem": undefined, "title": "Deeplink ml:settings", }, ], @@ -320,7 +277,6 @@ Array [ "data_frame_analytics", "ml:dataFrameAnalytics", ], - "renderItem": undefined, "title": "Jobs", }, Object { @@ -340,7 +296,6 @@ Array [ "data_frame_analytics", "ml:resultExplorer", ], - "renderItem": undefined, "title": "Deeplink ml:resultExplorer", }, Object { @@ -360,7 +315,6 @@ Array [ "data_frame_analytics", "ml:analyticsMap", ], - "renderItem": undefined, "title": "Deeplink ml:analyticsMap", }, ], @@ -393,7 +347,6 @@ Array [ "model_management", "ml:nodesOverview", ], - "renderItem": undefined, "title": "Deeplink ml:nodesOverview", }, Object { @@ -413,7 +366,6 @@ Array [ "model_management", "ml:nodes", ], - "renderItem": undefined, "title": "Deeplink ml:nodes", }, ], @@ -446,7 +398,6 @@ Array [ "data_visualizer", "ml:fileUpload", ], - "renderItem": undefined, "title": "File", }, Object { @@ -466,7 +417,6 @@ Array [ "data_visualizer", "ml:indexDataVisualizer", ], - "renderItem": undefined, "title": "Data view", }, Object { @@ -486,7 +436,6 @@ Array [ "data_visualizer", "ml:dataDrift", ], - "renderItem": undefined, "title": "Data drift", }, ], @@ -519,7 +468,6 @@ Array [ "aiops_labs", "ml:logRateAnalysis", ], - "renderItem": undefined, "title": "Deeplink ml:logRateAnalysis", }, Object { @@ -539,7 +487,6 @@ Array [ "aiops_labs", "ml:logPatternAnalysis", ], - "renderItem": undefined, "title": "Deeplink ml:logPatternAnalysis", }, Object { @@ -559,7 +506,6 @@ Array [ "aiops_labs", "ml:changePointDetections", ], - "renderItem": undefined, "title": "Deeplink ml:changePointDetections", }, ], @@ -608,65 +554,46 @@ Array [ "breadcrumbStatus": "hidden", "children": Array [ Object { - "children": Array [ - Object { - "children": undefined, - "deepLink": Object { - "baseUrl": "/mocked", - "href": "http://mocked/management", - "id": "management", - "title": "Deeplink management", - "url": "/mocked/management", - }, - "href": undefined, - "id": "management", - "isActive": false, - "path": Array [ - "project_settings_project_nav", - "settings", - "management", - ], - "renderItem": undefined, - "title": "Management", - }, - Object { - "children": undefined, - "deepLink": undefined, - "href": "https://cloud.elastic.co/deployments/123456789/security/users", - "id": "cloudLinkUserAndRoles", - "isActive": false, - "path": Array [ - "project_settings_project_nav", - "settings", - "cloudLinkUserAndRoles", - ], - "renderItem": undefined, - "title": "Mock Users & Roles", - }, - Object { - "children": undefined, - "deepLink": undefined, - "href": "https://cloud.elastic.co/account/billing", - "id": "cloudLinkBilling", - "isActive": false, - "path": Array [ - "project_settings_project_nav", - "settings", - "cloudLinkBilling", - ], - "renderItem": undefined, - "title": "Mock Billing & Subscriptions", - }, + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/management", + "id": "management", + "title": "Deeplink management", + "url": "/mocked/management", + }, + "href": undefined, + "id": "management", + "isActive": false, + "path": Array [ + "project_settings_project_nav", + "management", ], + "title": "Management", + }, + Object { + "children": undefined, "deepLink": undefined, - "href": undefined, - "id": "settings", + "href": "https://cloud.elastic.co/deployments/123456789/security/users", + "id": "cloudLinkUserAndRoles", + "isActive": false, + "path": Array [ + "project_settings_project_nav", + "cloudLinkUserAndRoles", + ], + "title": "Mock Users & Roles", + }, + Object { + "children": undefined, + "deepLink": undefined, + "href": "https://cloud.elastic.co/account/billing", + "id": "cloudLinkBilling", "isActive": false, "path": Array [ "project_settings_project_nav", - "settings", + "cloudLinkBilling", ], - "title": "", + "title": "Mock Billing & Subscriptions", }, ], "deepLink": undefined, diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/group_as_link.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/group_as_link.tsx deleted file mode 100644 index 092d243722cd4c..00000000000000 --- a/packages/shared-ux/chrome/navigation/src/ui/components/group_as_link.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 from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiTitle, - useGeneratedHtmlId, -} from '@elastic/eui'; - -import type { NavigateToUrlFn } from '../../../types/internal'; - -interface Props { - title: string; - href: string; - navigateToUrl: NavigateToUrlFn; - iconType?: string; -} - -export const GroupAsLink = ({ title, href, navigateToUrl, iconType }: Props) => { - const groupID = useGeneratedHtmlId(); - const titleID = `${groupID}__title`; - const TitleElement = 'h3'; - - return ( - - {iconType && ( - - - - )} - - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - { - e.preventDefault(); - e.stopPropagation(); - navigateToUrl(href); - }} - href={href} - > - - - {title} - - - - - - ); -}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation.test.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation.test.tsx index b804f65e31d6c7..a6a40347068e30 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation.test.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation.test.tsx @@ -40,12 +40,12 @@ describe('', () => { const { findByTestId } = render( - + - + - + @@ -62,10 +62,10 @@ describe('', () => { expect(await findByTestId(/nav-item-group1.item2/)).toBeVisible(); expect(await findByTestId(/nav-item-group1.group1A\s/)).toBeVisible(); expect(await findByTestId(/nav-item-group1.group1A.item1/)).toBeVisible(); - expect(await findByTestId(/nav-item-group1.group1A.group1A_1/)).toBeVisible(); + expect(await findByTestId(/nav-item-group1.group1A.group1A_1\s/)).toBeVisible(); // Click the last group to expand and show the last depth - (await findByTestId(/nav-item-group1.group1A.group1A_1/)).click(); + (await findByTestId(/nav-item-group1.group1A.group1A_1\s/)).click(); expect(await findByTestId(/nav-item-group1.group1A.group1A_1.item1/)).toBeVisible(); @@ -76,56 +76,56 @@ describe('', () => { expect(navTree.navigationTree).toEqual([ { - id: 'group1', - path: ['group1'], - title: '', - isActive: false, children: [ { - id: 'item1', - title: 'Item 1', href: 'https://foo', + id: 'item1', isActive: false, path: ['group1', 'item1'], + title: 'Item 1', }, { - id: 'item2', - title: 'Item 2', href: 'https://foo', + id: 'item2', isActive: false, path: ['group1', 'item2'], + title: 'Item 2', }, { - id: 'group1A', - title: 'Group1A', - isActive: false, - path: ['group1', 'group1A'], children: [ { - id: 'item1', href: 'https://foo', - title: 'Group 1A Item 1', + id: 'item1', isActive: false, path: ['group1', 'group1A', 'item1'], + title: 'Group 1A Item 1', }, { - id: 'group1A_1', - title: 'Group1A_1', - isActive: false, - path: ['group1', 'group1A', 'group1A_1'], children: [ { + href: 'https://foo', id: 'item1', - title: 'Group 1A_1 Item 1', isActive: false, - href: 'https://foo', path: ['group1', 'group1A', 'group1A_1', 'item1'], + title: 'Group 1A_1 Item 1', }, ], + id: 'group1A_1', + isActive: true, + path: ['group1', 'group1A', 'group1A_1'], + title: 'Group1A_1', }, ], + id: 'group1A', + isActive: true, + path: ['group1', 'group1A'], + title: 'Group1A', }, ], + id: 'group1', + isActive: true, + path: ['group1'], + title: '', }, ]); }); @@ -250,8 +250,8 @@ describe('', () => { onProjectNavigationChange={onProjectNavigationChange} > - - + + {/* Title from deeplink */} id="item1" link="item1" /> {/* Should not appear */} @@ -279,13 +279,13 @@ describe('', () => { id: 'root', path: ['root'], title: '', - isActive: false, + isActive: true, children: [ { id: 'group1', path: ['root', 'group1'], title: '', - isActive: false, + isActive: true, children: [ { id: 'item1', @@ -326,11 +326,11 @@ describe('', () => { onProjectNavigationChange={onProjectNavigationChange} > - - + + id="item1" link="notRegistered" /> - + id="item1" link="item1" /> @@ -352,128 +352,39 @@ describe('', () => { expect(navTree.navigationTree).toEqual([ { - id: 'root', - path: ['root'], - title: '', - isActive: false, children: [ { id: 'group1', + isActive: true, path: ['root', 'group1'], title: '', - isActive: false, }, { - id: 'group2', - path: ['root', 'group2'], - title: '', - isActive: false, children: [ { - id: 'item1', - path: ['root', 'group2', 'item1'], - title: 'Title from deeplink', - isActive: false, deepLink: { - id: 'item1', - title: 'Title from deeplink', baseUrl: '', - url: '', href: '', - }, - }, - ], - }, - ], - }, - ]); - }); - - test('should render custom react element', async () => { - const navLinks$: Observable = of([ - { - id: 'item1', - title: 'Title from deeplink', - baseUrl: '', - url: '', - href: '', - }, - ]); - - const onProjectNavigationChange = jest.fn(); - - const { findByTestId } = render( - - - - - link="item1"> -
Custom element
-
- - {(navNode) =>
{navNode.title}
} -
-
-
-
-
- ); - - await act(async () => { - jest.advanceTimersByTime(SET_NAVIGATION_DELAY); - }); - - expect(await findByTestId('my-custom-element')).toBeVisible(); - expect(await findByTestId('my-other-custom-element')).toBeVisible(); - expect((await findByTestId('my-other-custom-element')).textContent).toBe('Children prop'); - - expect(onProjectNavigationChange).toHaveBeenCalled(); - const lastCall = - onProjectNavigationChange.mock.calls[onProjectNavigationChange.mock.calls.length - 1]; - const [navTree] = lastCall; - - expect(navTree.navigationTree).toEqual([ - { - id: 'root', - path: ['root'], - title: '', - isActive: false, - children: [ - { - id: 'group1', - path: ['root', 'group1'], - title: '', - isActive: false, - children: [ - { - id: 'item1', - path: ['root', 'group1', 'item1'], - title: 'Title from deeplink', - renderItem: expect.any(Function), - isActive: false, - deepLink: { id: 'item1', title: 'Title from deeplink', - baseUrl: '', url: '', - href: '', }, - }, - { - id: 'item2', - href: 'http://foo', - path: ['root', 'group1', 'item2'], - title: 'Children prop', + id: 'item1', isActive: false, - renderItem: expect.any(Function), + path: ['root', 'group2', 'item1'], + title: 'Title from deeplink', }, ], + id: 'group2', + isActive: true, + path: ['root', 'group2'], + title: '', }, ], + id: 'root', + isActive: true, + path: ['root'], + title: '', }, ]); }); @@ -649,11 +560,11 @@ describe('', () => { ); - expect(await findByTestId(/nav-item-group1.item1/)).toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item1/)).dataset.testSubj).toMatch( + /nav-item-isActive/ ); - expect(await findByTestId(/nav-item-group1.item2/)).not.toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item2/)).dataset.testSubj).not.toMatch( + /nav-item-isActive/ ); await act(async () => { @@ -673,11 +584,11 @@ describe('', () => { ]); }); - expect(await findByTestId(/nav-item-group1.item1/)).not.toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item1/)).dataset.testSubj).not.toMatch( + /nav-item-isActive/ ); - expect(await findByTestId(/nav-item-group1.item2/)).toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item2/)).dataset.testSubj).toMatch( + /nav-item-isActive/ ); }); @@ -730,8 +641,8 @@ describe('', () => { jest.advanceTimersByTime(SET_NAVIGATION_DELAY); - expect(await findByTestId(/nav-item-group1.item1/)).toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item1/)).dataset.testSubj).toMatch( + /nav-item-isActive/ ); }); }); @@ -743,7 +654,7 @@ describe('', () => { const { findByTestId } = render( - + @@ -756,13 +667,13 @@ describe('', () => { expect(await findByTestId(/nav-item-group1.cloudLink2/)).toBeVisible(); expect(await findByTestId(/nav-item-group1.cloudLink3/)).toBeVisible(); - expect(await (await findByTestId(/nav-item-group1.cloudLink1/)).textContent).toBe( + expect((await findByTestId(/nav-item-group1.cloudLink1/)).textContent).toBe( 'Mock Users & RolesExternal link' ); - expect(await (await findByTestId(/nav-item-group1.cloudLink2/)).textContent).toBe( + expect((await findByTestId(/nav-item-group1.cloudLink2/)).textContent).toBe( 'Mock PerformanceExternal link' ); - expect(await (await findByTestId(/nav-item-group1.cloudLink3/)).textContent).toBe( + expect((await findByTestId(/nav-item-group1.cloudLink3/)).textContent).toBe( 'Mock Billing & SubscriptionsExternal link' ); }); diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx index 76180b799991ad..070f156943b278 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx @@ -85,7 +85,7 @@ function NavigationGroupInternalComp< )} {/* We render the children so they mount and can register themselves but visually they don't appear here in the DOM. They are rendered inside the - "items" prop (see ) */} + "items" prop (see ) */} {children} ); diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx index 540b9cc6afe08d..a48e0b771ece59 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx @@ -6,12 +6,12 @@ * Side Public License, v 1. */ -import React, { Fragment, ReactElement, ReactNode, useEffect, useMemo } from 'react'; +import React, { Fragment, useEffect, useMemo } from 'react'; -import type { AppDeepLinkId } from '@kbn/core-chrome-browser'; +import type { AppDeepLinkId, ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import { useNavigation as useNavigationServices } from '../../services'; -import type { ChromeProjectNavigationNodeEnhanced, NodeProps } from '../types'; import { useInitNavNode } from '../hooks'; +import type { NodeProps } from '../types'; import { useNavigation } from './navigation'; export interface Props< @@ -22,10 +22,6 @@ export interface Props< unstyled?: boolean; } -function isReactElement(element: ReactNode): element is ReactElement { - return React.isValidElement(element); -} - function NavigationItemComp< LinkId extends AppDeepLinkId = AppDeepLinkId, Id extends string = string, @@ -33,7 +29,7 @@ function NavigationItemComp< >(props: Props) { const { cloudLinks } = useNavigationServices(); const navigationContext = useNavigation(); - const navNodeRef = React.useRef(null); + const navNodeRef = React.useRef(null); const { children, node } = useMemo(() => { const { children: _children, ...rest } = props; @@ -44,14 +40,7 @@ function NavigationItemComp< }, [props]); const unstyled = props.unstyled ?? navigationContext.unstyled; - let renderItem: (() => ReactElement) | undefined; - - if (!unstyled && children && (typeof children === 'function' || isReactElement(children))) { - renderItem = - typeof children === 'function' ? () => children(navNodeRef.current) : () => children; - } - - const { navNode } = useInitNavNode({ ...node, children, renderItem }, { cloudLinks }); + const { navNode } = useInitNavNode({ ...node, children }, { cloudLinks }); useEffect(() => { navNodeRef.current = navNode; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx index 3e4a3c3327162d..1f60ade15930bf 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx @@ -7,28 +7,22 @@ */ import React, { FC, useEffect, useState } from 'react'; + import { - EuiCollapsibleNavGroup, - EuiIcon, - EuiLink, - EuiSideNav, - EuiSideNavItemType, - EuiText, + EuiCollapsibleNavItem, + EuiCollapsibleNavItemProps, + EuiCollapsibleNavSubItemGroupTitle, } from '@elastic/eui'; +import { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import classnames from 'classnames'; import type { BasePathService, NavigateToUrlFn } from '../../../types/internal'; -import { navigationStyles as styles } from '../../styles'; import { useNavigation as useServices } from '../../services'; -import { ChromeProjectNavigationNodeEnhanced } from '../types'; import { isAbsoluteLink } from '../../utils'; -import { GroupAsLink } from './group_as_link'; - -type RenderItem = EuiSideNavItemType['renderItem']; const navigationNodeToEuiItem = ( - item: ChromeProjectNavigationNodeEnhanced, + item: ChromeProjectNavigationNode, { navigateToUrl, basePath }: { navigateToUrl: NavigateToUrlFn; basePath: BasePathService } -): EuiSideNavItemType => { +): EuiCollapsibleNavSubItemGroupTitle | EuiCollapsibleNavItemProps => { const href = item.deepLink?.url ?? item.href; const id = item.path ? item.path.join('.') : item.id; const isExternal = Boolean(href) && isAbsoluteLink(href!); @@ -39,24 +33,16 @@ const navigationNodeToEuiItem = ( [`nav-item-isActive`]: isSelected, }); - const getRenderItem = (): RenderItem | undefined => { - if (!isExternal || item.renderItem) { - return item.renderItem; - } - - return () => ( -
- - {item.title} - -
- ); - }; - return { id, - name: item.title, + isGroupTitle: item.isGroupTitle, + title: item.title, isSelected, + accordionProps: { + ...item.accordionProps, + initialIsOpen: true, // FIXME open state is controlled on component mount + }, + linkProps: { external: isExternal }, onClick: href !== undefined ? (event: React.MouseEvent) => { @@ -65,20 +51,18 @@ const navigationNodeToEuiItem = ( } : undefined, href, - renderItem: getRenderItem(), items: item.children?.map((_item) => navigationNodeToEuiItem(_item, { navigateToUrl, basePath }) ), ['data-test-subj']: dataTestSubj, - ...(item.icon && { - icon: , - }), + icon: item.icon, + iconProps: { size: 's' }, }; }; interface Props { - navNode: ChromeProjectNavigationNodeEnhanced; - items?: ChromeProjectNavigationNodeEnhanced[]; + navNode: ChromeProjectNavigationNode; + items?: ChromeProjectNavigationNode[]; } export const NavigationSectionUI: FC = ({ navNode, items = [] }) => { @@ -90,8 +74,12 @@ export const NavigationSectionUI: FC = ({ navNode, items = [] }) => { const [doCollapseFromActiveState, setDoCollapseFromActiveState] = useState(true); // If the item has no link and no cildren, we don't want to render it - const itemHasLinkOrChildren = (item: ChromeProjectNavigationNodeEnhanced) => { + const itemHasLinkOrChildren = (item: ChromeProjectNavigationNode) => { + const isGroupTitle = Boolean(item.isGroupTitle); const hasLink = Boolean(item.deepLink) || Boolean(item.href); + if (isGroupTitle) { + return true; + } if (hasLink) { return true; } @@ -128,49 +116,39 @@ export const NavigationSectionUI: FC = ({ navNode, items = [] }) => { return null; } - const propsForGroupAsLink = groupIsLink + const propsForGroupAsLink: Partial = groupIsLink ? { - buttonElement: 'div' as const, - // If we don't force the state there is a little UI animation as if the - // accordion was openin/closing. We don't want any animation when it is a link. - forceState: 'closed' as const, - buttonContent: ( - - ), - arrowProps: { style: { display: 'none' } }, + linkProps: { + href: groupHref, + onClick: (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + navigateToUrl(groupHref); + }, + }, } : {}; return ( - { - setIsCollapsed(!isOpen); - setDoCollapseFromActiveState(false); + icon={icon} + iconProps={{ size: 'm' }} + accordionProps={{ + initialIsOpen: isActive, + forceState: isCollapsed ? 'closed' : 'open', + onToggle: (isOpen) => { + setIsCollapsed(!isOpen); + setDoCollapseFromActiveState(false); + }, + ...navNode.accordionProps, }} - forceState={isCollapsed ? 'closed' : 'open'} data-test-subj={`nav-bucket-${id}`} {...propsForGroupAsLink} - > - - - navigationNodeToEuiItem(item, { navigateToUrl, basePath }) - )} - css={styles.euiSideNavItems} - /> - - + items={filteredItems.map((item) => + navigationNodeToEuiItem(item, { navigateToUrl, basePath }) + )} + /> ); }; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_ui.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_ui.tsx index 898a3b68298215..113bfc0add6d60 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_ui.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_ui.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlyoutBody, EuiFlyoutFooter } from '@elastic/eui'; import React, { FC } from 'react'; interface Props { @@ -21,17 +21,12 @@ export const NavigationUI: FC = ({ children, unstyled, footerChildren, da {unstyled ? ( <>{children} ) : ( - - {children} - - {footerChildren && {footerChildren}} - + <> + + {children} + + {footerChildren && {footerChildren}} + )} ); diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx index 051beb931a3717..501695e5ae6a74 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx @@ -6,14 +6,13 @@ * Side Public License, v 1. */ -import { EuiCollapsibleNavGroup, EuiSideNav, EuiSideNavItemType } from '@elastic/eui'; +import { EuiCollapsibleNavItem } from '@elastic/eui'; import React, { FC } from 'react'; import useObservable from 'react-use/lib/useObservable'; import type { Observable } from 'rxjs'; import { RecentItem } from '../../../types/internal'; import { useNavigation as useServices } from '../../services'; -import { navigationStyles as styles } from '../../styles'; import { getI18nStrings } from '../i18n_strings'; @@ -42,40 +41,31 @@ export const RecentlyAccessed: FC = ({ return null; } - const navItems: Array> = [ - { - name: '', // no list header title - id: 'recents_root', - items: recentlyAccessed.map((recent) => { - const { id, label, link } = recent; - const href = basePath.prepend(link); + const navItems = recentlyAccessed.map((recent) => { + const { id, label, link } = recent; + const href = basePath.prepend(link); - return { - id, - name: label, - href, - onClick: (e: React.MouseEvent) => { - e.preventDefault(); - navigateToUrl(href); - }, - }; - }), - }, - ]; + return { + id, + title: label, + href, + onClick: (e: React.MouseEvent) => { + e.preventDefault(); + navigateToUrl(href); + }, + }; + }); return ( - - - + items={navItems} + /> ); }; diff --git a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.test.tsx b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.test.tsx index e6fddce7e5a75b..9a6c9d5598a75f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.test.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.test.tsx @@ -80,7 +80,7 @@ describe('', () => { }, ]; - const { findByTestId } = render( + const { findAllByTestId } = render( @@ -90,16 +90,8 @@ describe('', () => { jest.advanceTimersByTime(SET_NAVIGATION_DELAY); }); - expect(await findByTestId(/nav-item-group1.item1/)).toBeVisible(); - expect(await findByTestId(/nav-item-group1.item2/)).toBeVisible(); - expect(await findByTestId(/nav-item-group1.group1A\s/)).toBeVisible(); - expect(await findByTestId(/nav-item-group1.group1A.item1/)).toBeVisible(); - expect(await findByTestId(/nav-item-group1.group1A.group1A_1/)).toBeVisible(); - // Click the last group to expand and show the last depth - (await findByTestId(/nav-item-group1.group1A.group1A_1/)).click(); - - expect(await findByTestId(/nav-item-group1.group1A.group1A_1.item1/)).toBeVisible(); + (await findAllByTestId(/nav-item-group1.group1A.group1A_1/))[0].click(); expect(onProjectNavigationChange).toHaveBeenCalled(); const lastCall = @@ -120,7 +112,6 @@ describe('', () => { "group1", "item1", ], - "renderItem": undefined, "title": "Item 1", }, Object { @@ -133,7 +124,6 @@ describe('', () => { "group1", "item2", ], - "renderItem": undefined, "title": "Item 2", }, Object { @@ -149,7 +139,6 @@ describe('', () => { "group1A", "item1", ], - "renderItem": undefined, "title": "Group 1A Item 1", }, Object { @@ -166,7 +155,6 @@ describe('', () => { "group1A_1", "item1", ], - "renderItem": undefined, "title": "Group 1A_1 Item 1", }, ], @@ -291,7 +279,6 @@ describe('', () => { "group1", "item1", ], - "renderItem": undefined, "title": "Title from deeplink", }, Object { @@ -311,7 +298,6 @@ describe('', () => { "group1", "item2", ], - "renderItem": undefined, "title": "Overwrite deeplink title", }, ], @@ -394,7 +380,6 @@ describe('', () => { "group1", "item1", ], - "renderItem": undefined, "title": "Absolute link", }, ], @@ -556,11 +541,11 @@ describe('', () => { jest.advanceTimersByTime(SET_NAVIGATION_DELAY); }); - expect(await findByTestId(/nav-item-group1.item1/)).toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item1/)).dataset.testSubj).toMatch( + /nav-item-isActive/ ); - expect(await findByTestId(/nav-item-group1.item2/)).not.toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item2/)).dataset.testSubj).not.toMatch( + /nav-item-isActive/ ); }); @@ -619,8 +604,8 @@ describe('', () => { jest.advanceTimersByTime(SET_NAVIGATION_DELAY); }); - expect(await findByTestId(/nav-item-group1.item1/)).toHaveClass( - 'euiSideNavItemButton-isSelected' + expect((await findByTestId(/nav-item-group1.item1/)).dataset.testSubj).toMatch( + /nav-item-isActive/ ); }); }); @@ -703,17 +688,12 @@ describe('', () => { ); expect( - await ( - await findByTestId( - /nav-item-project_settings_project_nav.settings.cloudLinkUserAndRoles/ - ) - ).textContent + (await findByTestId(/nav-item-project_settings_project_nav.cloudLinkUserAndRoles/)) + .textContent ).toBe('Mock Users & RolesExternal link'); expect( - await ( - await findByTestId(/nav-item-project_settings_project_nav.settings.cloudLinkBilling/) - ).textContent + (await findByTestId(/nav-item-project_settings_project_nav.cloudLinkBilling/)).textContent ).toBe('Mock Billing & SubscriptionsExternal link'); }); }); diff --git a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx index 4cdb108ef426b7..2457fa44a50968 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/default_navigation.tsx @@ -72,23 +72,18 @@ const getDefaultNavigationTree = ( breadcrumbStatus: 'hidden', children: [ { - id: 'settings', - children: [ - { - link: 'management', - title: i18n.translate('sharedUXPackages.chrome.sideNavigation.mngt', { - defaultMessage: 'Management', - }), - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], + link: 'management', + title: i18n.translate('sharedUXPackages.chrome.sideNavigation.mngt', { + defaultMessage: 'Management', + }), + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', }, ], }, diff --git a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts index f569115250e111..cedfd9c1b91e9b 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/hooks/use_init_navnode.ts @@ -19,13 +19,7 @@ import { CloudLinks } from '../../cloud_links'; import { useNavigation as useNavigationServices } from '../../services'; import { isAbsoluteLink } from '../../utils'; import { useNavigation } from '../components/navigation'; -import { - ChromeProjectNavigationNodeEnhanced, - NodeProps, - NodePropsEnhanced, - RegisterFunction, - UnRegisterFunction, -} from '../types'; +import { NodeProps, NodePropsEnhanced, RegisterFunction, UnRegisterFunction } from '../types'; import { useRegisterTreeNode } from './use_register_tree_node'; function getIdFromNavigationNode< @@ -135,7 +129,7 @@ function createInternalNavNode< path: string[] | null, isActive: boolean, { cloudLinks }: { cloudLinks: CloudLinks } -): ChromeProjectNavigationNodeEnhanced | null { +): ChromeProjectNavigationNode | null { validateNodeProps(_navNode); const { children, link, cloudLink, ...navNode } = _navNode; @@ -185,9 +179,9 @@ export const useInitNavNode = < /** * Map of children nodes */ - const [childrenNodes, setChildrenNodes] = useState< - Record - >({}); + const [childrenNodes, setChildrenNodes] = useState>( + {} + ); const isMounted = useRef(false); diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index eeff6afd945e99..c014678265ce9f 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -6,84 +6,61 @@ * Side Public License, v 1. */ -import React, { FC, useCallback, useState } from 'react'; -import { of } from 'rxjs'; -import { ComponentMeta } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import type { ChromeNavLink } from '@kbn/core-chrome-browser'; +import { useState } from '@storybook/addons'; +import { ComponentMeta } from '@storybook/react'; +import React, { EventHandler, FC, PropsWithChildren, MouseEvent } from 'react'; +import { BehaviorSubject, of } from 'rxjs'; import { EuiButton, - EuiButtonIcon, - EuiCollapsibleNav, + EuiCollapsibleNavBeta, + EuiCollapsibleNavBetaProps, EuiFlexGroup, EuiFlexItem, + EuiHeader, + EuiHeaderSection, EuiLink, + EuiPageTemplate, EuiText, - EuiThemeProvider, EuiTitle, } from '@elastic/eui'; -import { css } from '@emotion/react'; + +import type { ChromeNavLink, ChromeProjectNavigationNode } from '@kbn/core-chrome-browser'; import { NavigationStorybookMock, navLinksMock } from '../../mocks'; import mdx from '../../README.mdx'; -import { NavigationProvider } from '../services'; -import { DefaultNavigation } from './default_navigation'; import type { NavigationServices } from '../../types'; +import { NavigationProvider } from '../services'; import { Navigation } from './components'; -import type { NonEmptyArray, ProjectNavigationDefinition } from './types'; +import { DefaultNavigation } from './default_navigation'; import { getPresets } from './nav_tree_presets'; +import type { GroupDefinition, NonEmptyArray, ProjectNavigationDefinition } from './types'; const storybookMock = new NavigationStorybookMock(); -const SIZE_OPEN = 248; -const SIZE_CLOSED = 40; - -const NavigationWrapper: FC = ({ children }) => { - const [isOpen, setIsOpen] = useState(true); - - const collabsibleNavCSS = css` - border-inline-end-width: 1, - display: flex, - flex-direction: row, - `; - - const CollapseButton = () => { - const buttonCSS = css` - margin-left: -32px; - position: fixed; - z-index: 1000; - `; - return ( - - - - ); - }; - - const toggleOpen = useCallback(() => { - setIsOpen(!isOpen); - }, [isOpen, setIsOpen]); - +const NavigationWrapper: FC< + PropsWithChildren<{ clickAction?: EventHandler; clickActionText?: string }> & + Partial +> = (props) => { return ( - - } - > - {isOpen && children} - - + <> + + + + + + + + {props.clickAction ? ( + + {props.clickActionText ?? 'Click me'} + + ) : ( +

Hello world

+ )} +
+
+ ); }; @@ -123,30 +100,25 @@ const simpleNavigationDefinition: ProjectNavigationDefinition = { defaultIsCollapsed: false, children: [ { - id: 'root', - children: [ - { - id: 'item1', - title: 'Get started', - }, - { - id: 'item2', - title: 'Alerts', - }, - { - id: 'item3', - title: 'Dashboards', - }, - { - id: 'item4', - title: 'External link', - href: 'https://elastic.co', - }, - { - id: 'item5', - title: 'Another link', - }, - ], + id: 'item1', + title: 'Get started', + }, + { + id: 'item2', + title: 'Alerts', + }, + { + id: 'item3', + title: 'Dashboards', + }, + { + id: 'item4', + title: 'External link', + href: 'https://elastic.co', + }, + { + id: 'item5', + title: 'Another link', }, { id: 'group:settings', @@ -205,21 +177,16 @@ const navigationDefinition: ProjectNavigationDefinition = { defaultIsCollapsed: false, children: [ { - id: 'root', - children: [ - { - id: 'item1', - title: 'Get started', - }, - { - id: 'item2', - title: 'Alerts', - }, - { - id: 'item3', - title: 'Some other node', - }, - ], + id: 'item1', + title: 'Get started', + }, + { + id: 'item2', + title: 'Alerts', + }, + { + id: 'item3', + title: 'Some other node', }, { id: 'group:settings', @@ -333,24 +300,22 @@ export const WithUIComponents = (args: NavigationServices) => { icon="logoObservability" defaultIsCollapsed={false} > - - id="item1" link="item1" /> - - {(navNode) => { - return ( -
- {`Render prop: ${navNode.id} - ${navNode.title}`} -
- ); - }} -
- -
- Title in ReactNode -
-
- -
+ id="item1" link="item1" /> + + {(navNode) => { + return ( +
+ {`Render prop: ${navNode.id} - ${navNode.title}`} +
+ ); + }} +
+ +
+ Title in ReactNode +
+
+ @@ -370,12 +335,10 @@ export const WithUIComponents = (args: NavigationServices) => { breadcrumbStatus="hidden" icon="gear" > - - - - - - + + + +
@@ -551,3 +514,121 @@ export const CreativeUI = (args: NavigationServices) => { ); }; + +export const UpdatingState = (args: NavigationServices) => { + const simpleGroupDef: GroupDefinition = { + type: 'navGroup', + id: 'observability_project_nav', + title: 'Observability', + icon: 'logoObservability', + children: [ + { + id: 'aiops', + title: 'AIOps', + icon: 'branch', + children: [ + { + title: 'Anomaly detection', + id: 'ml:anomalyDetection', + link: 'ml:anomalyDetection', + }, + { + title: 'Log Rate Analysis', + id: 'ml:logRateAnalysis', + link: 'ml:logRateAnalysis', + }, + { + title: 'Change Point Detections', + link: 'ml:changePointDetections', + id: 'ml:changePointDetections', + }, + { + title: 'Job Notifications', + link: 'ml:notifications', + id: 'ml:notifications', + }, + ], + }, + { + id: 'project_settings_project_nav', + title: 'Project settings', + icon: 'gear', + children: [ + { id: 'management', link: 'management' }, + { id: 'integrations', link: 'integrations' }, + { id: 'fleet', link: 'fleet' }, + ], + }, + ], + }; + const firstSection = simpleGroupDef.children![0]; + const firstSectionFirstChild = firstSection.children![0]; + const secondSection = simpleGroupDef.children![1]; + const secondSectionFirstChild = secondSection.children![0]; + + const activeNodeSets: ChromeProjectNavigationNode[][][] = [ + [ + [ + { + ...simpleGroupDef, + path: [simpleGroupDef.id], + } as unknown as ChromeProjectNavigationNode, + { + ...firstSection, + path: [simpleGroupDef.id, firstSection.id], + } as unknown as ChromeProjectNavigationNode, + { + ...firstSectionFirstChild, + path: [simpleGroupDef.id, firstSection.id, firstSectionFirstChild.id], + } as unknown as ChromeProjectNavigationNode, + ], + ], + [ + [ + { + ...simpleGroupDef, + path: [simpleGroupDef.id], + } as unknown as ChromeProjectNavigationNode, + { + ...secondSection, + path: [simpleGroupDef.id, secondSection.id], + } as unknown as ChromeProjectNavigationNode, + { + ...secondSectionFirstChild, + path: [simpleGroupDef.id, secondSection.id, secondSectionFirstChild.id], + } as unknown as ChromeProjectNavigationNode, + ], + ], + ]; + + // use state to track which element of activeNodeSets is active + const [activeNodeIndex, setActiveNodeIndex] = useState(0); + const changeActiveNode = () => { + const value = (activeNodeIndex + 1) % 2; // toggle between 0 and 1 + setActiveNodeIndex(value); + }; + + const activeNodes$ = new BehaviorSubject([]); + activeNodes$.next(activeNodeSets[activeNodeIndex]); + + const services = storybookMock.getServices({ + ...args, + activeNodes$, + navLinks$: of([...navLinksMock, ...deepLinks]), + onProjectNavigationChange: (updated) => { + action('Update chrome navigation')(JSON.stringify(updated, null, 2)); + }, + }); + + return ( + + + + + + ); +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/types.ts b/packages/shared-ux/chrome/navigation/src/ui/types.ts index 5175425b6ada48..e7c642fc9d0b98 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/types.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/types.ts @@ -6,13 +6,14 @@ * Side Public License, v 1. */ -import type { ReactElement, ReactNode } from 'react'; +import type { ReactNode } from 'react'; + +import type { EuiAccordionProps } from '@elastic/eui'; import type { AppDeepLinkId, ChromeProjectNavigationNode, NodeDefinition, } from '@kbn/core-chrome-browser'; - import type { RecentlyAccessedProps } from './components'; export type NonEmptyArray = [T, ...T[]]; @@ -45,11 +46,6 @@ export interface NodePropsEnhanced< Id extends string = string, ChildrenId extends string = Id > extends NodeProps { - /** - * This function correspond to the same "itemRender" function that can be passed to - * the EuiSideNavItemType (see navigation_section_ui.tsx) - */ - renderItem?: () => ReactElement; /** * Forces the node to be active. This is used to force a collapisble nav group to be open * even if the URL does not match any of the nodes in the group. @@ -57,17 +53,6 @@ export interface NodePropsEnhanced< isActive?: boolean; } -/** - * @internal - */ -export interface ChromeProjectNavigationNodeEnhanced extends ChromeProjectNavigationNode { - /** - * This function correspond to the same "itemRender" function that can be passed to - * the EuiSideNavItemType (see navigation_section_ui.tsx) - */ - renderItem?: () => ReactElement; -} - /** The preset that can be pass to the NavigationBucket component */ export type NavigationGroupPreset = 'analytics' | 'devtools' | 'ml' | 'management'; @@ -101,6 +86,10 @@ export interface GroupDefinition< * `true`: the group will be collapsed event if any of its children nodes matches the current URL. */ defaultIsCollapsed?: boolean; + /* + * Pass props to the EUI accordion component used to represent a nav group + */ + accordionProps?: Partial; preset?: NavigationGroupPreset; } @@ -172,7 +161,7 @@ export type UnRegisterFunction = (id: string) => void; * * A function to register a navigation node on its parent. */ -export type RegisterFunction = (navNode: ChromeProjectNavigationNodeEnhanced) => { +export type RegisterFunction = (navNode: ChromeProjectNavigationNode) => { /** The function to unregister the node. */ unregister: UnRegisterFunction; /** The full path of the node in the navigation tree. */ diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 55cf3960ab0bd6..f0c012c19f564a 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -25,136 +25,135 @@ const navigationTree: NavigationTreeDefinition = { title: 'Observability', icon: 'logoObservability', defaultIsCollapsed: false, + accordionProps: { + arrowProps: { css: { display: 'none' } }, + }, breadcrumbStatus: 'hidden', children: [ { - id: 'discover-dashboard-alerts-slos', + title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { + defaultMessage: 'Log Explorer', + }), + link: 'observability-log-explorer', + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { + defaultMessage: 'Dashboards', + }), + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); + }, + }, + { + link: 'observability-overview:alerts', + }, + { + link: 'observability-overview:slos', + }, + { + id: 'aiops', + title: 'AIOps', + accordionProps: { + arrowProps: { css: { display: 'none' } }, + }, children: [ { - title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { - defaultMessage: 'Log Explorer', + title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { + defaultMessage: 'Anomaly detection', }), - link: 'observability-log-explorer', + link: 'ml:anomalyDetection', }, { - title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { - defaultMessage: 'Dashboards', + title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { + defaultMessage: 'Log rate analysis', }), - link: 'dashboards', + link: 'ml:logRateAnalysis', getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); + return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); }, }, { - link: 'observability-overview:alerts', - }, - { - link: 'observability-overview:slos', + title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { + defaultMessage: 'Change point detection', + }), + link: 'ml:changePointDetections', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.includes(prepend('/app/ml/aiops/change_point_detection')); + }, }, { - id: 'aiops', - title: 'AIOps', - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { - defaultMessage: 'Anomaly detection', - }), - link: 'ml:anomalyDetection', - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { - defaultMessage: 'Log rate analysis', - }), - link: 'ml:logRateAnalysis', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { - defaultMessage: 'Change point detection', - }), - link: 'ml:changePointDetections', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes( - prepend('/app/ml/aiops/change_point_detection') - ); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { - defaultMessage: 'Job notifications', - }), - link: 'ml:notifications', - }, - ], + title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { + defaultMessage: 'Job notifications', + }), + link: 'ml:notifications', }, ], }, { - id: 'applications', - children: [ - { - id: 'apm', - title: i18n.translate('xpack.serverlessObservability.nav.applications', { - defaultMessage: 'Applications', - }), - children: [ - { - link: 'apm:services', - getIsActive: ({ pathNameSerialized, prepend }) => { - const regex = /app\/apm\/.*service.*/; - return regex.test(pathNameSerialized); - }, - }, - { - link: 'apm:traces', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/traces')); - }, - }, - { - link: 'apm:dependencies', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); - }, - }, - ], - }, - ], + id: 'groups-spacer-1', + isGroupTitle: true, }, { - id: 'cases-vis', + id: 'apm', + title: i18n.translate('xpack.serverlessObservability.nav.applications', { + defaultMessage: 'Applications', + }), + accordionProps: { + arrowProps: { css: { display: 'none' } }, + }, children: [ { - link: 'observability-overview:cases', + link: 'apm:services', + getIsActive: ({ pathNameSerialized }) => { + const regex = /app\/apm\/.*service.*/; + return regex.test(pathNameSerialized); + }, }, { - title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { - defaultMessage: 'Visualizations', - }), - link: 'visualize', + link: 'apm:traces', getIsActive: ({ pathNameSerialized, prepend }) => { - return ( - pathNameSerialized.startsWith(prepend('/app/visualize')) || - pathNameSerialized.startsWith(prepend('/app/lens')) || - pathNameSerialized.startsWith(prepend('/app/maps')) - ); + return pathNameSerialized.startsWith(prepend('/app/apm/traces')); }, }, - ], - }, - { - id: 'on-boarding', - children: [ { - title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { - defaultMessage: 'Add data', - }), - link: 'observabilityOnboarding', + link: 'apm:dependencies', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); + }, }, ], }, + { + id: 'groups-spacer-2', + isGroupTitle: true, + }, + { + link: 'observability-overview:cases', + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { + defaultMessage: 'Visualizations', + }), + link: 'visualize', + getIsActive: ({ pathNameSerialized, prepend }) => { + return ( + pathNameSerialized.startsWith(prepend('/app/visualize')) || + pathNameSerialized.startsWith(prepend('/app/lens')) || + pathNameSerialized.startsWith(prepend('/app/maps')) + ); + }, + }, + { + id: 'groups-spacer-3', + isGroupTitle: true, + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { + defaultMessage: 'Add data', + }), + link: 'observabilityOnboarding', + }, ], }, ], @@ -178,29 +177,24 @@ const navigationTree: NavigationTreeDefinition = { breadcrumbStatus: 'hidden', children: [ { - id: 'settings', - children: [ - { - link: 'management', - title: i18n.translate('xpack.serverlessObservability.nav.mngt', { - defaultMessage: 'Management', - }), - }, - { - link: 'integrations', - }, - { - link: 'fleet', - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], + link: 'management', + title: i18n.translate('xpack.serverlessObservability.nav.mngt', { + defaultMessage: 'Management', + }), + }, + { + link: 'integrations', + }, + { + link: 'fleet', + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', }, ], }, diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx index 047b490fcb137e..b6f1cdbaa56ffa 100644 --- a/x-pack/plugins/serverless_search/public/layout/nav.tsx +++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx @@ -25,6 +25,9 @@ const navigationTree: NavigationTreeDefinition = { title: 'Elasticsearch', icon: 'logoElasticsearch', defaultIsCollapsed: false, + accordionProps: { + arrowProps: { css: { display: 'none' } }, + }, breadcrumbStatus: 'hidden', children: [ { @@ -39,77 +42,75 @@ const navigationTree: NavigationTreeDefinition = { title: i18n.translate('xpack.serverlessSearch.nav.devTools', { defaultMessage: 'Dev Tools', }), - children: [{ link: 'dev_tools:console' }, { link: 'dev_tools:searchprofiler' }], + isGroupTitle: true, }, + { link: 'dev_tools:console' }, + { link: 'dev_tools:searchprofiler' }, { id: 'explore', title: i18n.translate('xpack.serverlessSearch.nav.explore', { defaultMessage: 'Explore', }), - children: [ - { - link: 'discover', - }, - { - link: 'dashboards', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); - }, - }, - { - link: 'visualize', - getIsActive: ({ pathNameSerialized, prepend }) => { - return ( - pathNameSerialized.startsWith(prepend('/app/visualize')) || - pathNameSerialized.startsWith(prepend('/app/lens')) || - pathNameSerialized.startsWith(prepend('/app/maps')) - ); - }, - }, - { - link: 'management:triggersActions', - title: i18n.translate('xpack.serverlessSearch.nav.alerts', { - defaultMessage: 'Alerts', - }), - }, - ], + isGroupTitle: true, }, + { + link: 'discover', + }, + { + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); + }, + }, + { + link: 'visualize', + getIsActive: ({ pathNameSerialized, prepend }) => { + return ( + pathNameSerialized.startsWith(prepend('/app/visualize')) || + pathNameSerialized.startsWith(prepend('/app/lens')) || + pathNameSerialized.startsWith(prepend('/app/maps')) + ); + }, + }, + { + link: 'management:triggersActions', + title: i18n.translate('xpack.serverlessSearch.nav.alerts', { + defaultMessage: 'Alerts', + }), + }, + { id: 'content', title: i18n.translate('xpack.serverlessSearch.nav.content', { defaultMessage: 'Content', }), - children: [ - { - title: i18n.translate('xpack.serverlessSearch.nav.content.indices', { - defaultMessage: 'Index Management', - }), - link: 'management:index_management', - breadcrumbStatus: - 'hidden' /* management sub-pages set their breadcrumbs themselves */, - }, - { - title: i18n.translate('xpack.serverlessSearch.nav.content.pipelines', { - defaultMessage: 'Pipelines', - }), - link: 'management:ingest_pipelines', - breadcrumbStatus: - 'hidden' /* management sub-pages set their breadcrumbs themselves */, - }, - ], + isGroupTitle: true, }, + { + title: i18n.translate('xpack.serverlessSearch.nav.content.indices', { + defaultMessage: 'Index Management', + }), + link: 'management:index_management', + breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */, + }, + { + title: i18n.translate('xpack.serverlessSearch.nav.content.pipelines', { + defaultMessage: 'Pipelines', + }), + link: 'management:ingest_pipelines', + breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */, + }, + { id: 'security', title: i18n.translate('xpack.serverlessSearch.nav.security', { defaultMessage: 'Security', }), - children: [ - { - link: 'management:api_keys', - breadcrumbStatus: - 'hidden' /* management sub-pages set their breadcrumbs themselves */, - }, - ], + isGroupTitle: true, + }, + { + link: 'management:api_keys', + breadcrumbStatus: 'hidden' /* management sub-pages set their breadcrumbs themselves */, }, ], }, @@ -125,30 +126,25 @@ const navigationTree: NavigationTreeDefinition = { breadcrumbStatus: 'hidden', children: [ { - id: 'settings', - children: [ - { - link: 'management', - title: i18n.translate('xpack.serverlessSearch.nav.mngt', { - defaultMessage: 'Management', - }), - }, - { - id: 'cloudLinkDeployment', - cloudLink: 'deployment', - title: i18n.translate('xpack.serverlessSearch.nav.performance', { - defaultMessage: 'Performance', - }), - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], + link: 'management', + title: i18n.translate('xpack.serverlessSearch.nav.mngt', { + defaultMessage: 'Management', + }), + }, + { + id: 'cloudLinkDeployment', + cloudLink: 'deployment', + title: i18n.translate('xpack.serverlessSearch.nav.performance', { + defaultMessage: 'Performance', + }), + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', }, ], }, diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 3c3b10a5d03c8e..56351af9b43f18 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -23,6 +23,7 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { const testSubjects = ctx.getService('testSubjects'); const browser = ctx.getService('browser'); const retry = ctx.getService('retry'); + const log = ctx.getService('log'); async function getByVisibleText( selector: string | (() => Promise), @@ -93,16 +94,20 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { } }, async expectSectionExists(sectionId: NavigationId) { + log.debug('ServerlessCommonNavigation.sidenav.expectSectionExists', sectionId); await testSubjects.existOrFail(`~nav-bucket-${sectionId}`); }, async isSectionOpen(sectionId: NavigationId) { await this.expectSectionExists(sectionId); const section = await testSubjects.find(`~nav-bucket-${sectionId}`); - const collapseBtn = await section.findByCssSelector(`[aria-controls="${sectionId}"]`); + const collapseBtn = await section.findByCssSelector( + `[aria-controls="${sectionId}"][aria-expanded]` + ); const isExpanded = await collapseBtn.getAttribute('aria-expanded'); return isExpanded === 'true'; }, async expectSectionOpen(sectionId: NavigationId) { + log.debug('ServerlessCommonNavigation.sidenav.expectSectionOpen', sectionId); await this.expectSectionExists(sectionId); await retry.waitFor(`section ${sectionId} to be open`, async () => { const isOpen = await this.isSectionOpen(sectionId); @@ -117,11 +122,14 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { }); }, async openSection(sectionId: NavigationId) { + log.debug('ServerlessCommonNavigation.sidenav.openSection', sectionId); await this.expectSectionExists(sectionId); const isOpen = await this.isSectionOpen(sectionId); if (isOpen) return; const section = await testSubjects.find(`~nav-bucket-${sectionId}`); - const collapseBtn = await section.findByCssSelector(`[aria-controls="${sectionId}"]`); + const collapseBtn = await section.findByCssSelector( + `[aria-controls="${sectionId}"][aria-expanded]` + ); await collapseBtn.click(); await this.expectSectionOpen(sectionId); }, @@ -130,7 +138,9 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { const isOpen = await this.isSectionOpen(sectionId); if (!isOpen) return; const section = await testSubjects.find(`~nav-bucket-${sectionId}`); - const collapseBtn = await section.findByCssSelector(`[aria-controls="${sectionId}"]`); + const collapseBtn = await section.findByCssSelector( + `[aria-controls="${sectionId}"][aria-expanded]` + ); await collapseBtn.click(); await this.expectSectionClosed(sectionId); }, @@ -143,6 +153,10 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { await testSubjects.click('~breadcrumb-home'); }, async expectBreadcrumbExists(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + log.debug( + 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbExists', + JSON.stringify(by) + ); if ('deepLinkId' in by) { await testSubjects.existOrFail(`~breadcrumb-deepLinkId-${by.deepLinkId}`); } else { @@ -161,6 +175,10 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { } }, async expectBreadcrumbTexts(expectedBreadcrumbTexts: string[]) { + log.debug( + 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbTexts', + JSON.stringify(expectedBreadcrumbTexts) + ); await retry.try(async () => { const breadcrumbsContainer = await testSubjects.find('breadcrumbs'); const breadcrumbs = await breadcrumbsContainer.findAllByTestSubject('~breadcrumb'); diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 13eaca8526366d..9b7e0d545394d2 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -48,9 +48,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { // navigate to discover await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'discover' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: `Explore` }); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'discover' }); - await expect(await browser.getCurrentUrl()).contain('/app/discover'); + expect(await browser.getCurrentUrl()).contain('/app/discover'); // navigate to a different section await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:index_management' }); @@ -73,20 +72,16 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { it("management apps from the sidenav hide the 'stack management' root from the breadcrumbs", async () => { await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:triggersActions' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Explore', 'Alerts', 'Rules']); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Alerts', 'Rules']); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:index_management' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ - 'Content', - 'Index Management', - 'Indices', - ]); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Index Management', 'Indices']); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:ingest_pipelines' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Content', 'Ingest Pipelines']); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Ingest Pipelines']); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:api_keys' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Security', 'API keys']); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['API keys']); }); it('navigate management', async () => { @@ -104,7 +99,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.search.clickOnOption(0); await svlCommonNavigation.search.hideSearch(); - await expect(await browser.getCurrentUrl()).contain('/app/discover'); + expect(await browser.getCurrentUrl()).contain('/app/discover'); }); it('does not show cases in sidebar navigation', async () => { From ac2d3db3ff6c81c56b1d3a1c938b6ac778721e9c Mon Sep 17 00:00:00 2001 From: christineweng <18648970+christineweng@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:31:12 -0500 Subject: [PATCH 11/22] [Security Solution] fix change alert status flaky tests (#166538) ## Summary This PR unskips and fixes some cypress test related to changing alert status per https://github.com/elastic/kibana/issues/166415 --- .../alerts/changing_alert_status.cy.ts | 34 ++++++------------- .../cypress/tasks/alerts.ts | 6 +++- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts index 2bc367c88654ed..c01cd6522c9752 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/changing_alert_status.cy.ts @@ -120,13 +120,14 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () }); context('Marking alerts as acknowledged', () => { beforeEach(() => { + login(); deleteAlertsAndRules(); createRule(getNewRule()); visit(ALERTS_URL); waitForAlertsToPopulate(); selectCountTable(); }); - it.skip('Mark one alert as acknowledged when more than one open alerts are selected', () => { + it('Mark one alert as acknowledged when more than one open alerts are selected', () => { cy.get(ALERTS_COUNT) .invoke('text') .then((alertNumberString) => { @@ -139,6 +140,7 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () cy.get(TAKE_ACTION_POPOVER_BTN).should('exist'); markAcknowledgedFirstAlert(); + waitForAlerts(); const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged; cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`); sumAlertCountFromAlertCountTable((sumAlerts) => { @@ -228,7 +230,7 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () }); }); - it.skip('Closes one alert when more than one opened alerts are selected', () => { + it('Closes one alert when more than one opened alerts are selected', () => { cy.get(ALERTS_COUNT) .invoke('text') .then((alertNumberString) => { @@ -308,8 +310,7 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () }); }); - // TODO: Are you sure that read only role should be able to close alerts? - context.skip('Changing alert status with read only role', () => { + context('Changing alert status with read only role', () => { beforeEach(() => { login(ROLES.t2_analyst); deleteAlertsAndRules(); @@ -319,12 +320,11 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () selectCountTable(); }); - it.skip('Mark one alert as acknowledged when more than one open alerts are selected', () => { + it('Mark one alert as acknowledged when more than one open alerts are selected', () => { cy.get(ALERTS_COUNT) .invoke('text') .then((alertNumberString) => { const numberOfAlerts = alertNumberString.split(' ')[0]; - const numberOfAlertsToBeMarkedAcknowledged = 1; const numberOfAlertsToBeSelected = 3; cy.get(TAKE_ACTION_POPOVER_BTN).should('not.exist'); @@ -332,19 +332,10 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () cy.get(TAKE_ACTION_POPOVER_BTN).should('exist'); markAcknowledgedFirstAlert(); - const expectedNumberOfAlerts = +numberOfAlerts - numberOfAlertsToBeMarkedAcknowledged; - cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlerts} alerts`); + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); // user with read only role cannot mark alerts as acknowledged sumAlertCountFromAlertCountTable((sumAlerts) => { - expect(sumAlerts).to.eq(parseAlertsCountToInt(expectedNumberOfAlerts)); - }); - goToAcknowledgedAlerts(); - waitForAlerts(); - - cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlertsToBeMarkedAcknowledged} alert`); - - sumAlertCountFromAlertCountTable((sumAlerts) => { - expect(sumAlerts).to.eq(parseAlertsCountToInt(numberOfAlertsToBeMarkedAcknowledged)); + expect(sumAlerts).to.eq(parseAlertsCountToInt(numberOfAlerts)); }); }); }); @@ -369,16 +360,11 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, () closeAlerts(); waitForAlerts(); - const expectedNumberOfAlertsAfterClosing = +numberOfAlerts - numberOfAlertsToBeClosed; - cy.get(ALERTS_COUNT).should('have.text', `${expectedNumberOfAlertsAfterClosing} alerts`); + cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlerts} alerts`); // user with read only role cannot mark alerts as acknowledged sumAlertCountFromAlertCountTable((sumAlerts) => { - expect(sumAlerts).to.eq(parseAlertsCountToInt(expectedNumberOfAlertsAfterClosing)); + expect(sumAlerts).to.eq(parseAlertsCountToInt(numberOfAlerts)); }); - goToClosedAlerts(); - waitForAlerts(); - - cy.get(ALERTS_COUNT).should('have.text', `${numberOfAlertsToBeClosed} alerts`); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts index b96667dd3d3de9..de6b4b95deea78 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts @@ -113,6 +113,7 @@ export const openAddEndpointExceptionFromAlertActionButton = () => { }; export const closeFirstAlert = () => { expandFirstAlertActions(); + cy.get(CLOSE_ALERT_BTN).should('be.visible'); cy.get(CLOSE_ALERT_BTN).click(); cy.get(CLOSE_ALERT_BTN).should('not.exist'); }; @@ -128,6 +129,7 @@ export const expandFirstAlertActions = () => { waitForAlerts(); const togglePopover = () => { + cy.get(TIMELINE_CONTEXT_MENU_BTN).first().should('be.visible'); cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click(); cy.get(TIMELINE_CONTEXT_MENU_BTN) .first() @@ -191,6 +193,7 @@ export const closePageFilterPopover = (filterIndex: number) => { }; export const clearAllSelections = (filterIndex: number) => { + cy.scrollTo('top'); recurse( () => { cy.get(CONTROL_FRAME_TITLE).eq(filterIndex).realHover(); @@ -264,7 +267,7 @@ export const goToOpenedAlerts = () => { export const openFirstAlert = () => { expandFirstAlertActions(); cy.get(OPEN_ALERT_BTN).should('be.visible'); - cy.get(OPEN_ALERT_BTN).click({ force: true }); + cy.get(OPEN_ALERT_BTN).click(); }; export const openAlerts = () => { @@ -303,6 +306,7 @@ export const goToAcknowledgedAlerts = () => { export const markAcknowledgedFirstAlert = () => { expandFirstAlertActions(); + cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).should('be.visible'); cy.get(MARK_ALERT_ACKNOWLEDGED_BTN).click(); }; From 02b7c962473f8b0804357e2f2271e6c7b4965c45 Mon Sep 17 00:00:00 2001 From: Ying Mao Date: Wed, 27 Sep 2023 17:32:26 -0400 Subject: [PATCH 12/22] [Response Ops][Alerting] Using `refresh=true` instead of `refresh='wait_for'` when writing alerts (#166296) Resolves https://github.com/elastic/kibana/issues/163953 ## Summary Changes `refresh='wait_for'` to `refresh=true` when bulk indexing alerts from the alerting framework and the rule registry. For persistence alerts, `refresh=false` is used when the rule execution is a preview. ## Notes I deployed this image to the serverless QA environment and compared execution times between this branch and the default QA version with an index threshold rule that creates and active alert each run. Default QA version: * avg 8.16 seconds * P99 15.5 seconds QA using this image: * avg: 0.6 seconds * P99 1.7 seconds --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Ryland Herrick --- .../server/alerts_client/alerts_client.test.ts | 18 +++++++++--------- .../server/alerts_client/alerts_client.ts | 2 +- .../task_runner_alerts_client.test.ts | 2 +- .../server/utils/create_lifecycle_executor.ts | 2 +- .../create_persistence_rule_type_wrapper.ts | 2 +- .../create_security_rule_type_wrapper.ts | 3 +-- .../server/lib/detection_engine/types.ts | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 2b9a1e0cf0b84b..8fa4f291f17db1 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -376,7 +376,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -588,7 +588,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -821,7 +821,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -1047,7 +1047,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -1465,7 +1465,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -2128,7 +2128,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -2395,7 +2395,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -2571,7 +2571,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { @@ -2743,7 +2743,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts index 90fbba5969de81..1f790ae1f7cabd 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts @@ -408,7 +408,7 @@ export class AlertsClient< try { const response = await esClient.bulk({ - refresh: 'wait_for', + refresh: true, index: this.indexTemplateAndPattern.alias, require_alias: !this.isUsingDataStreams(), body: bulkBody, diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index cc1d162a1ecc7a..24a47357aa0be8 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -483,7 +483,7 @@ describe('Task Runner', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: 'wait_for', + refresh: true, require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts index deac218c9c49e4..91d30fae7b3dc9 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts @@ -383,7 +383,7 @@ export const createLifecycleExecutor = }, event, ]), - refresh: 'wait_for', + refresh: true, }); } else { logger.debug( diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts index 3cf7dc59370a32..31304339c16001 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts @@ -354,7 +354,7 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper const bulkResponse = await ruleDataClientWriter.bulk({ body: [...duplicateAlertUpdates, ...mapAlertsToBulkCreate(augmentedAlerts)], - refresh: 'wait_for', + refresh: true, }); if (bulkResponse == null) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts index c3fb701458238d..9614939a86840c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/create_security_rule_type_wrapper.ts @@ -169,11 +169,10 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper = }; const { - actions, schedule: { interval }, } = completeRule.ruleConfig; - const refresh = actions.length ? 'wait_for' : false; + const refresh = isPreview ? false : true; ruleExecutionLogger.debug(`Starting Security Rule execution (interval: ${interval})`); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts index 4b3f73a88d4af7..e2bf376a460dbf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts @@ -9,4 +9,4 @@ import type { Filter } from '@kbn/es-query'; export type PartialFilter = Partial; -export type RefreshTypes = false | 'wait_for'; +export type RefreshTypes = boolean; From c84248c87dd308f72ed7d78733d25433d1caa504 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Wed, 27 Sep 2023 23:56:42 +0200 Subject: [PATCH 13/22] [asset manager] use metrics data plugin (#166756) ## Summary Closes https://github.com/elastic/kibana/issues/166636 - use metrics_data_access plugin to dynamically retrieve indices where needed - add basic `/assets/hosts` api test --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Jason Rhodes --- x-pack/plugins/asset_manager/kibana.jsonc | 3 +- .../accessors/hosts/get_hosts_by_signals.ts | 9 ++- .../server/lib/accessors/index.ts | 2 + .../services/get_services_by_signals.ts | 4 +- .../server/lib/asset_accessor.ts | 3 + .../server/lib/collectors/containers.ts | 6 +- .../server/lib/collectors/hosts.ts | 4 + .../server/lib/collectors/index.ts | 13 ++-- .../server/lib/collectors/pods.ts | 4 + .../server/lib/collectors/services.ts | 12 ++- x-pack/plugins/asset_manager/server/plugin.ts | 1 + .../server/routes/assets/hosts.ts | 1 - x-pack/plugins/asset_manager/server/types.ts | 4 +- x-pack/plugins/asset_manager/tsconfig.json | 3 +- .../tests/with_signals_source/hosts.ts | 54 ++++++++++++++ .../tests/with_signals_source/index.ts | 2 + .../tests/with_signals_source/services.ts | 74 +++++++++---------- 17 files changed, 141 insertions(+), 58 deletions(-) create mode 100644 x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/hosts.ts diff --git a/x-pack/plugins/asset_manager/kibana.jsonc b/x-pack/plugins/asset_manager/kibana.jsonc index a3bfb9261456fa..49b1b59838d9c3 100644 --- a/x-pack/plugins/asset_manager/kibana.jsonc +++ b/x-pack/plugins/asset_manager/kibana.jsonc @@ -12,7 +12,8 @@ "optionalPlugins": [ ], "requiredPlugins": [ - "apmDataAccess" + "apmDataAccess", + "metricsDataAccess" ], "browser": false, "server": true, diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts_by_signals.ts b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts_by_signals.ts index a58bfac79c3d37..4fad9e301a89d0 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts_by_signals.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/hosts/get_hosts_by_signals.ts @@ -12,11 +12,18 @@ import { collectHosts } from '../../collectors/hosts'; export async function getHostsBySignals( options: GetHostsOptionsInjected ): Promise<{ hosts: Asset[] }> { + const metricsIndices = await options.metricsClient.getMetricIndices({ + savedObjectsClient: options.soClient, + }); + const { assets } = await collectHosts({ client: options.esClient, from: options.from, to: options.to, - sourceIndices: options.sourceIndices, + sourceIndices: { + metrics: metricsIndices, + logs: options.sourceIndices.logs, + }, }); return { hosts: assets, diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/index.ts b/x-pack/plugins/asset_manager/server/lib/accessors/index.ts index d75490b002e97c..f5cf4d38fadc89 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/index.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/index.ts @@ -7,12 +7,14 @@ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { APMDataAccessConfig } from '@kbn/apm-data-access-plugin/server'; +import { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { SavedObjectsClientContract } from '@kbn/core/server'; import { AssetManagerConfig } from '../../types'; export interface InjectedValues { sourceIndices: AssetManagerConfig['sourceIndices']; getApmIndices: (soClient: SavedObjectsClientContract) => Promise; + metricsClient: MetricsDataClient; } export type OptionsWithInjectedValues = T & InjectedValues; diff --git a/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services_by_signals.ts b/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services_by_signals.ts index 8618feb288b7bc..ab8de39adb3015 100644 --- a/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services_by_signals.ts +++ b/x-pack/plugins/asset_manager/server/lib/accessors/services/get_services_by_signals.ts @@ -31,7 +31,9 @@ export async function getServicesBySignals( client: options.esClient, from: options.from, to: options.to, - apmIndices, + sourceIndices: { + apm: apmIndices, + }, filters, }); diff --git a/x-pack/plugins/asset_manager/server/lib/asset_accessor.ts b/x-pack/plugins/asset_manager/server/lib/asset_accessor.ts index 9f4f33097879de..73c2064e483117 100644 --- a/x-pack/plugins/asset_manager/server/lib/asset_accessor.ts +++ b/x-pack/plugins/asset_manager/server/lib/asset_accessor.ts @@ -6,6 +6,7 @@ */ import { APMDataAccessConfig } from '@kbn/apm-data-access-plugin/server'; +import { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { SavedObjectsClientContract } from '@kbn/core/server'; import { Asset } from '../../common/types_api'; import { AssetManagerConfig } from '../types'; @@ -21,6 +22,7 @@ interface AssetAccessorClassOptions { sourceIndices: AssetManagerConfig['sourceIndices']; source: AssetManagerConfig['lockedSource']; getApmIndices: (soClient: SavedObjectsClientContract) => Promise; + metricsClient: MetricsDataClient; } export class AssetAccessor { @@ -31,6 +33,7 @@ export class AssetAccessor { ...options, sourceIndices: this.options.sourceIndices, getApmIndices: this.options.getApmIndices, + metricsClient: this.options.metricsClient, }; } diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/containers.ts b/x-pack/plugins/asset_manager/server/lib/collectors/containers.ts index c693fc47302d77..a96a89ea8a3999 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/containers.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/containers.ts @@ -16,9 +16,13 @@ export async function collectContainers({ sourceIndices, afterKey, }: CollectorOptions) { + if (!sourceIndices?.metrics || !sourceIndices?.logs) { + throw new Error('missing required metrics/logs indices'); + } + const { metrics, logs } = sourceIndices; const dsl: estypes.SearchRequest = { - index: [logs, metrics], + index: [metrics, logs], size: QUERY_MAX_SIZE, collapse: { field: 'container.id', diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/hosts.ts b/x-pack/plugins/asset_manager/server/lib/collectors/hosts.ts index f6821d73f251d8..750c9fdac21b9c 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/hosts.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/hosts.ts @@ -16,6 +16,10 @@ export async function collectHosts({ sourceIndices, afterKey, }: CollectorOptions) { + if (!sourceIndices?.metrics || !sourceIndices?.logs) { + throw new Error('missing required metrics/logs indices'); + } + const { metrics, logs } = sourceIndices; const dsl: estypes.SearchRequest = { index: [metrics, logs], diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/index.ts b/x-pack/plugins/asset_manager/server/lib/collectors/index.ts index 3b426200657c5b..f1d79e749cd973 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/index.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/index.ts @@ -8,7 +8,6 @@ import { estypes } from '@elastic/elasticsearch'; import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; import { ElasticsearchClient } from '@kbn/core/server'; -import { AssetManagerConfig } from '../../types'; import { Asset } from '../../../common/types_api'; export const QUERY_MAX_SIZE = 10000; @@ -19,17 +18,15 @@ export interface CollectorOptions { client: ElasticsearchClient; from: string; to: string; - sourceIndices: AssetManagerConfig['sourceIndices']; + sourceIndices?: { + apm?: APMIndices; + metrics?: string; + logs?: string; + }; afterKey?: estypes.SortResults; filters?: estypes.QueryDslQueryContainer[]; } -type OmitSourceIndices = Omit; - -export type ServicesCollectorOptions = OmitSourceIndices & { - apmIndices: APMIndices; -}; - export interface CollectorResult { assets: Asset[]; afterKey?: estypes.SortResults; diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts b/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts index 104cab1d361e4c..5cbf357e695696 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/pods.ts @@ -10,6 +10,10 @@ import { Asset } from '../../../common/types_api'; import { CollectorOptions, QUERY_MAX_SIZE } from '.'; export async function collectPods({ client, from, to, sourceIndices, afterKey }: CollectorOptions) { + if (!sourceIndices?.metrics || !sourceIndices?.logs) { + throw new Error('missing required metrics/logs indices'); + } + const { metrics, logs } = sourceIndices; const dsl: estypes.SearchRequest = { index: [metrics, logs], diff --git a/x-pack/plugins/asset_manager/server/lib/collectors/services.ts b/x-pack/plugins/asset_manager/server/lib/collectors/services.ts index 062c3a06054cd6..cf41dc96cd3f72 100644 --- a/x-pack/plugins/asset_manager/server/lib/collectors/services.ts +++ b/x-pack/plugins/asset_manager/server/lib/collectors/services.ts @@ -7,17 +7,21 @@ import { estypes } from '@elastic/elasticsearch'; import { Asset } from '../../../common/types_api'; -import { ServicesCollectorOptions, QUERY_MAX_SIZE } from '.'; +import { CollectorOptions, QUERY_MAX_SIZE } from '.'; export async function collectServices({ client, from, to, - apmIndices, + sourceIndices, afterKey, filters = [], -}: ServicesCollectorOptions) { - const { transaction, error, metric } = apmIndices; +}: CollectorOptions) { + if (!sourceIndices?.apm) { + throw new Error('missing required apm indices'); + } + + const { transaction, error, metric } = sourceIndices.apm; const musts: estypes.QueryDslQueryContainer[] = [ ...filters, { diff --git a/x-pack/plugins/asset_manager/server/plugin.ts b/x-pack/plugins/asset_manager/server/plugin.ts index 41114fadbbc7b7..6693e6037a8362 100644 --- a/x-pack/plugins/asset_manager/server/plugin.ts +++ b/x-pack/plugins/asset_manager/server/plugin.ts @@ -59,6 +59,7 @@ export class AssetManagerServerPlugin source: this.config.lockedSource, sourceIndices: this.config.sourceIndices, getApmIndices: plugins.apmDataAccess.getApmIndices, + metricsClient: plugins.metricsDataAccess.client, }); const router = core.http.createRouter(); diff --git a/x-pack/plugins/asset_manager/server/routes/assets/hosts.ts b/x-pack/plugins/asset_manager/server/routes/assets/hosts.ts index 68ed4baaeb5c8f..e17ad95f81a24d 100644 --- a/x-pack/plugins/asset_manager/server/routes/assets/hosts.ts +++ b/x-pack/plugins/asset_manager/server/routes/assets/hosts.ts @@ -36,7 +36,6 @@ export function hostsRoutes({ router, assetAccessor, }: SetupRouteOptions) { - // GET /assets/hosts router.get( { path: `${ASSET_MANAGER_API_BASE}/assets/hosts`, diff --git a/x-pack/plugins/asset_manager/server/types.ts b/x-pack/plugins/asset_manager/server/types.ts index d964d3133c61e8..380d48aa0c7fee 100644 --- a/x-pack/plugins/asset_manager/server/types.ts +++ b/x-pack/plugins/asset_manager/server/types.ts @@ -11,13 +11,13 @@ import { ApmDataAccessPluginSetup, ApmDataAccessPluginStart, } from '@kbn/apm-data-access-plugin/server'; +import { MetricsDataPluginSetup } from '@kbn/metrics-data-access-plugin/server'; export interface ElasticsearchAccessorOptions { esClient: ElasticsearchClient; } export const INDEX_DEFAULTS = { - metrics: 'metricbeat-*,metrics-*', logs: 'filebeat-*,logs-*', }; @@ -29,7 +29,6 @@ export const configSchema = schema.object({ // that value is propagated everywhere. For now, we duplicate the value here. sourceIndices: schema.object( { - metrics: schema.string({ defaultValue: INDEX_DEFAULTS.metrics }), logs: schema.string({ defaultValue: INDEX_DEFAULTS.logs }), }, { defaultValue: INDEX_DEFAULTS } @@ -48,6 +47,7 @@ export type AssetManagerConfig = TypeOf; export interface AssetManagerPluginSetupDependencies { apmDataAccess: ApmDataAccessPluginSetup; + metricsDataAccess: MetricsDataPluginSetup; } export interface AssetManagerPluginStartDependencies { apmDataAccess: ApmDataAccessPluginStart; diff --git a/x-pack/plugins/asset_manager/tsconfig.json b/x-pack/plugins/asset_manager/tsconfig.json index 9527af19396e55..d7663856f0513a 100644 --- a/x-pack/plugins/asset_manager/tsconfig.json +++ b/x-pack/plugins/asset_manager/tsconfig.json @@ -20,6 +20,7 @@ "@kbn/core-elasticsearch-server", "@kbn/core-http-request-handler-context-server", "@kbn/datemath", - "@kbn/apm-data-access-plugin" + "@kbn/apm-data-access-plugin", + "@kbn/metrics-data-access-plugin" ] } diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/hosts.ts b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/hosts.ts new file mode 100644 index 00000000000000..87b9a96944b565 --- /dev/null +++ b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/hosts.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { timerange, infra } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { ASSETS_ENDPOINT } from '../constants'; +import { FtrProviderContext } from '../../types'; + +const HOSTS_ASSETS_ENDPOINT = `${ASSETS_ENDPOINT}/hosts`; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const synthtrace = getService('infraSynthtraceEsClient'); + + describe('GET /assets/hosts', () => { + beforeEach(async () => { + await synthtrace.clean(); + }); + + it('should return hosts', async () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + await synthtrace.index(generateHostsData({ from, to, count: 5 })); + + const response = await supertest + .get(HOSTS_ASSETS_ENDPOINT) + .query({ + from, + to, + }) + .expect(200); + + expect(response.body).to.have.property('hosts'); + expect(response.body.hosts.length).to.equal(5); + }); + }); +} + +function generateHostsData({ from, to, count = 1 }: { from: string; to: string; count: number }) { + const range = timerange(from, to); + + const hosts = Array(count) + .fill(0) + .map((_, idx) => infra.host(`my-host-${idx}`)); + + return range + .interval('1m') + .rate(1) + .generator((timestamp, index) => hosts.map((host) => host.metrics().timestamp(timestamp))); +} diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/index.ts b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/index.ts index 72e685549dc299..7c9c5fb4ae6262 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/index.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/index.ts @@ -9,5 +9,7 @@ import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Asset Manager API Endpoints - with signals source', () => { loadTestFile(require.resolve('./basics')); + loadTestFile(require.resolve('./hosts')); + loadTestFile(require.resolve('./services')); }); } diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/services.ts b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/services.ts index 320f4d4c0fc502..1dea627a2a9181 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/services.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/with_signals_source/services.ts @@ -17,53 +17,51 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const synthtrace = getService('apmSynthtraceEsClient'); - describe('asset management', () => { + describe('GET /assets/services', () => { beforeEach(async () => { await synthtrace.clean(); }); - describe('GET /assets/services', () => { - it('should return services', async () => { - const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); - const to = new Date().toISOString(); - await synthtrace.index(generateServicesData({ from, to, count: 2 })); + it('should return services', async () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + await synthtrace.index(generateServicesData({ from, to, count: 2 })); - const response = await supertest - .get(SERVICES_ASSETS_ENDPOINT) - .query({ - from, - to, - }) - .expect(200); + const response = await supertest + .get(SERVICES_ASSETS_ENDPOINT) + .query({ + from, + to, + }) + .expect(200); - expect(response.body).to.have.property('services'); - expect(response.body.services.length).to.equal(2); - }); + expect(response.body).to.have.property('services'); + expect(response.body.services.length).to.equal(2); + }); - it('should return services running on specified host', async () => { - const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); - const to = new Date().toISOString(); - await synthtrace.index(generateServicesData({ from, to, count: 5 })); + it('should return services running on specified host', async () => { + const from = new Date(Date.now() - 1000 * 60 * 2).toISOString(); + const to = new Date().toISOString(); + await synthtrace.index(generateServicesData({ from, to, count: 5 })); - const response = await supertest - .get(SERVICES_ASSETS_ENDPOINT) - .query({ - from, - to, - parent: 'my-host-1', - }) - .expect(200); + const response = await supertest + .get(SERVICES_ASSETS_ENDPOINT) + .query({ + from, + to, + parent: 'my-host-1', + }) + .expect(200); - expect(response.body).to.have.property('services'); - expect(response.body.services.length).to.equal(1); - expect(omit(response.body.services[0], ['@timestamp'])).to.eql({ - 'asset.kind': 'service', - 'asset.id': 'service-1', - 'asset.ean': 'service:service-1', - 'asset.references': [], - 'asset.parents': [], - 'service.environment': 'production', - }); + expect(response.body).to.have.property('services'); + expect(response.body.services.length).to.equal(1); + expect(omit(response.body.services[0], ['@timestamp'])).to.eql({ + 'asset.kind': 'service', + 'asset.id': 'service-1', + 'asset.ean': 'service:service-1', + 'asset.references': [], + 'asset.parents': [], + 'service.environment': 'production', }); }); }); From 90a8b32393b40774ad8fa3de924df2da85ffae5a Mon Sep 17 00:00:00 2001 From: Philippe Oberti Date: Thu, 28 Sep 2023 00:01:28 +0200 Subject: [PATCH 14/22] [Security Solution] expandable flyout - fix footer not always visible (#167074) --- .../src/components/left_section.tsx | 6 +++--- .../src/components/right_section.tsx | 6 +++--- .../public/flyout/left/content.tsx | 13 +++++++++++-- .../public/flyout/left/header.tsx | 19 ++++++++++--------- .../public/flyout/left/index.tsx | 11 ++--------- .../public/flyout/right/header.tsx | 7 +------ 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/packages/kbn-expandable-flyout/src/components/left_section.tsx b/packages/kbn-expandable-flyout/src/components/left_section.tsx index 25958fbb332b77..d388923c01d69f 100644 --- a/packages/kbn-expandable-flyout/src/components/left_section.tsx +++ b/packages/kbn-expandable-flyout/src/components/left_section.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; import { LEFT_SECTION } from './test_ids'; @@ -26,12 +26,12 @@ interface LeftSectionProps { */ export const LeftSection: React.FC = ({ component, width }: LeftSectionProps) => { const style = useMemo( - () => ({ height: '100%', width: `${width * 100}%`, overflowY: 'scroll' }), + () => ({ height: '100%', width: `${width * 100}%` }), [width] ); return ( - {component} + {component} ); }; diff --git a/packages/kbn-expandable-flyout/src/components/right_section.tsx b/packages/kbn-expandable-flyout/src/components/right_section.tsx index b6020a54bc39f5..7857c2b4fba485 100644 --- a/packages/kbn-expandable-flyout/src/components/right_section.tsx +++ b/packages/kbn-expandable-flyout/src/components/right_section.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexItem } from '@elastic/eui'; import React, { useMemo } from 'react'; import { RIGHT_SECTION } from './test_ids'; @@ -29,13 +29,13 @@ export const RightSection: React.FC = ({ width, }: RightSectionProps) => { const style = useMemo( - () => ({ height: '100%', width: `${width * 100}%`, overflowY: 'scroll' }), + () => ({ height: '100%', width: `${width * 100}%` }), [width] ); return ( - {component} + {component} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/left/content.tsx b/x-pack/plugins/security_solution/public/flyout/left/content.tsx index 27fb60800d40ae..b16d1dd3adfebc 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/content.tsx @@ -5,9 +5,10 @@ * 2.0. */ -import { EuiFlyoutBody } from '@elastic/eui'; +import { EuiFlyoutBody, useEuiBackgroundColor } from '@elastic/eui'; import type { VFC } from 'react'; import React, { useMemo } from 'react'; +import { css } from '@emotion/react'; import type { LeftPanelPaths } from '.'; import { tabs } from './tabs'; @@ -27,7 +28,15 @@ export const PanelContent: VFC = ({ selectedTabId }) => { return tabs.filter((tab) => tab.visible).find((tab) => tab.id === selectedTabId)?.content; }, [selectedTabId]); - return {selectedTabContent}; + return ( + + {selectedTabContent} + + ); }; PanelContent.displayName = 'PanelContent'; diff --git a/x-pack/plugins/security_solution/public/flyout/left/header.tsx b/x-pack/plugins/security_solution/public/flyout/left/header.tsx index df11d7bf36db72..50c53cd5dcd8f9 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/header.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiFlyoutHeader, EuiTab, EuiTabs } from '@elastic/eui'; +import { EuiFlyoutHeader, EuiTab, EuiTabs, useEuiBackgroundColor } from '@elastic/eui'; import type { VFC } from 'react'; import React, { memo } from 'react'; import { css } from '@emotion/react'; @@ -44,14 +44,15 @@ export const PanelHeader: VFC = memo(({ selectedTabId, setSele )); return ( - - + + {renderTabs} diff --git a/x-pack/plugins/security_solution/public/flyout/left/index.tsx b/x-pack/plugins/security_solution/public/flyout/left/index.tsx index 73138b7ecb266e..a6e4e865adfa8f 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/index.tsx @@ -7,8 +7,6 @@ import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; -import { useEuiBackgroundColor } from '@elastic/eui'; -import { css } from '@emotion/react'; import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { PanelHeader } from './header'; @@ -60,15 +58,10 @@ export const LeftPanel: FC> = memo(({ path }) => { }; return ( -
+ <> -
+ ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/header.tsx b/x-pack/plugins/security_solution/public/flyout/right/header.tsx index 67425b6eb35657..80d809af07116b 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/header.tsx @@ -49,12 +49,7 @@ export const PanelHeader: VFC = memo( )); return ( - + {flyoutIsExpandable && (
Date: Thu, 28 Sep 2023 00:04:35 +0200 Subject: [PATCH 15/22] =?UTF-8?q?[Security=20Solution]=20Bad=20user=20expe?= =?UTF-8?q?rience=20when=20hovering=20some=20icons=20on=20n=E2=80=A6=20(#1?= =?UTF-8?q?67300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../right/components/insights_summary_row.tsx | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx index 9ffc267c3ccae0..5aacae978c7210 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx @@ -8,8 +8,15 @@ import type { ReactElement, VFC } from 'react'; import React from 'react'; import { css } from '@emotion/react'; -import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiSkeletonText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { + EuiIcon, + EuiFlexGroup, + EuiFlexItem, + EuiHealth, + EuiSkeletonText, + useEuiTheme, +} from '@elastic/eui'; import { FormattedCount } from '../../../common/components/formatted_number'; export interface InsightsSummaryRowProps { @@ -58,6 +65,8 @@ export const InsightsSummaryRow: VFC = ({ color, 'data-test-subj': dataTestSubj, }) => { + const { euiTheme } = useEuiTheme(); + const loadingDataTestSubj = `${dataTestSubj}Loading`; if (loading) { return ( @@ -88,19 +97,26 @@ export const InsightsSummaryRow: VFC = ({ return ( - + + + Date: Wed, 27 Sep 2023 17:28:03 -0500 Subject: [PATCH 16/22] [RAM] Mark disabled alerts as Untracked in both Stack and o11y (#164788) ## Summary Part of #164059 Implements the `Untracked` lifecycle status, and applies it to alerts when their corresponding rule is disabled. Screenshot 2023-08-24 at 4 24 45 PM Screenshot 2023-08-24 at 4 56 32 PM Screenshot 2023-08-24 at 4 56 17 PM ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../alert_lifecycle_status_badge/index.tsx | 23 ++++++- .../src/alerts_as_data_status.ts | 6 +- .../plugins/alerting/common/alert_summary.ts | 1 + .../alerts_client/alerts_client.test.ts | 47 ++++++++++++++ .../server/alerts_client/alerts_client.ts | 61 ++++++++++++++++++- .../alerts_client/legacy_alerts_client.ts | 4 ++ .../alerting/server/alerts_client/types.ts | 1 + .../methods/aggregate/aggregate_rules.test.ts | 2 + .../bulk_delete/bulk_delete_rules.test.ts | 2 + .../methods/bulk_edit/bulk_edit_rules.test.ts | 2 + .../rule/methods/create/create_rule.test.ts | 2 + .../get_schedule_frequency.test.ts | 2 + .../lib/alert_summary_from_event_log.test.ts | 14 +++++ .../lib/alert_summary_from_event_log.ts | 3 + x-pack/plugins/alerting/server/plugin.ts | 3 + .../lib/create_new_api_key_set.test.ts | 2 + .../alerting/server/rules_client/lib/index.ts | 2 +- ..._rule_alerts.ts => untrack_rule_alerts.ts} | 58 ++++++++++++++---- .../rules_client/methods/bulk_disable.ts | 23 +++++-- .../server/rules_client/methods/disable.ts | 12 +++- .../rules_client/tests/bulk_disable.test.ts | 12 ++-- .../rules_client/tests/bulk_enable.test.ts | 2 + .../tests/clear_expired_snoozes.test.ts | 2 + .../server/rules_client/tests/delete.test.ts | 2 + .../server/rules_client/tests/disable.test.ts | 20 +++--- .../server/rules_client/tests/enable.test.ts | 2 + .../server/rules_client/tests/find.test.ts | 2 + .../server/rules_client/tests/get.test.ts | 2 + .../tests/get_action_error_log.test.ts | 2 + .../tests/get_alert_state.test.ts | 2 + .../tests/get_alert_summary.test.ts | 5 ++ .../tests/get_execution_log.test.ts | 2 + .../rules_client/tests/get_tags.test.ts | 2 + .../tests/list_rule_types.test.ts | 2 + .../rules_client/tests/mute_all.test.ts | 2 + .../rules_client/tests/mute_instance.test.ts | 2 + .../server/rules_client/tests/resolve.test.ts | 2 + .../rules_client/tests/run_soon.test.ts | 2 + .../rules_client/tests/unmute_all.test.ts | 2 + .../tests/unmute_instance.test.ts | 2 + .../server/rules_client/tests/update.test.ts | 2 + .../rules_client/tests/update_api_key.test.ts | 2 + .../alerting/server/rules_client/types.ts | 4 ++ .../rules_client_conflict_retries.test.ts | 2 + .../server/rules_client_factory.test.ts | 6 ++ .../alerting/server/rules_client_factory.ts | 10 +++ .../infra/public/common/alerts/constants.ts | 22 ++++++- .../tabs/alerts/alerts_status_filter.tsx | 7 +++ .../plugins/observability/common/typings.ts | 7 ++- .../components/alerts_status_filter.tsx | 8 ++- .../components/alert_search_bar/constants.ts | 16 ++++- .../alerts_flyout/alerts_flyout_body.tsx | 6 +- .../task_manager/server/task_scheduling.ts | 11 +++- .../lib/rule_api/rule_summary.test.ts | 2 + .../rule_details/components/rule.test.tsx | 23 ++++++- .../sections/rule_details/components/rule.tsx | 2 + .../components/rule_alert_list.tsx | 17 +++++- .../components/rule_route.test.tsx | 1 + .../rule_details/components/test_helpers.ts | 1 + .../sections/rule_details/components/types.ts | 1 + .../tests/alerting/group1/disable.ts | 6 +- .../tests/alerting/group1/event_log.ts | 1 + .../alerting/group1/get_alert_summary.ts | 13 ++++ 63 files changed, 453 insertions(+), 58 deletions(-) rename x-pack/plugins/alerting/server/rules_client/lib/{recover_rule_alerts.ts => untrack_rule_alerts.ts} (51%) diff --git a/packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx b/packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx index 35519fba7dd1e2..7d06bc45b5c033 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx +++ b/packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx @@ -9,7 +9,7 @@ import React, { memo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiBadge, EuiBadgeProps } from '@elastic/eui'; -import { AlertStatus, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; +import { AlertStatus, ALERT_STATUS_RECOVERED, ALERT_STATUS_UNTRACKED } from '@kbn/rule-data-utils'; export interface AlertLifecycleStatusBadgeProps { alertStatus: AlertStatus; @@ -37,15 +37,27 @@ const FLAPPING_LABEL = i18n.translate( } ); +const UNTRACKED_LABEL = i18n.translate( + 'alertsUIShared.components.alertLifecycleStatusBadge.untrackedLabel', + { + defaultMessage: 'Untracked', + } +); + interface BadgeProps { label: string; color: string; + isDisabled?: boolean; iconProps?: { iconType: EuiBadgeProps['iconType']; }; } const getBadgeProps = (alertStatus: AlertStatus, flapping: boolean | undefined): BadgeProps => { + if (alertStatus === ALERT_STATUS_UNTRACKED) { + return { label: UNTRACKED_LABEL, color: 'default', isDisabled: true }; + } + // Prefer recovered over flapping if (alertStatus === ALERT_STATUS_RECOVERED) { return { @@ -82,10 +94,15 @@ export const AlertLifecycleStatusBadge = memo((props: AlertLifecycleStatusBadgeP const castedFlapping = castFlapping(flapping); - const { label, color, iconProps } = getBadgeProps(alertStatus, castedFlapping); + const { label, color, iconProps, isDisabled } = getBadgeProps(alertStatus, castedFlapping); return ( - + {label} ); diff --git a/packages/kbn-rule-data-utils/src/alerts_as_data_status.ts b/packages/kbn-rule-data-utils/src/alerts_as_data_status.ts index cb36ce339e79a9..d7e1ca921e23d8 100644 --- a/packages/kbn-rule-data-utils/src/alerts_as_data_status.ts +++ b/packages/kbn-rule-data-utils/src/alerts_as_data_status.ts @@ -8,5 +8,9 @@ export const ALERT_STATUS_ACTIVE = 'active'; export const ALERT_STATUS_RECOVERED = 'recovered'; +export const ALERT_STATUS_UNTRACKED = 'untracked'; -export type AlertStatus = typeof ALERT_STATUS_ACTIVE | typeof ALERT_STATUS_RECOVERED; +export type AlertStatus = + | typeof ALERT_STATUS_ACTIVE + | typeof ALERT_STATUS_RECOVERED + | typeof ALERT_STATUS_UNTRACKED; diff --git a/x-pack/plugins/alerting/common/alert_summary.ts b/x-pack/plugins/alerting/common/alert_summary.ts index ed6cf325e20b1b..d982f60e82bec2 100644 --- a/x-pack/plugins/alerting/common/alert_summary.ts +++ b/x-pack/plugins/alerting/common/alert_summary.ts @@ -40,4 +40,5 @@ export interface AlertStatus { activeStartDate?: string; flapping: boolean; maintenanceWindowIds?: string[]; + tracked: boolean; } diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 8fa4f291f17db1..a5378245b7a02e 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -3026,6 +3026,53 @@ describe('Alerts Client', () => { expect(recoveredAlert.hit).toBeUndefined(); }); }); + + describe('setAlertStatusToUntracked()', () => { + test('should call updateByQuery on provided ruleIds', async () => { + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>( + alertsClientParams + ); + + const opts = { + maxAlerts, + ruleLabel: `test: rule-name`, + flappingSettings: DEFAULT_FLAPPING_SETTINGS, + activeAlertsFromState: {}, + recoveredAlertsFromState: {}, + }; + await alertsClient.initializeExecution(opts); + + await alertsClient.setAlertStatusToUntracked(['test-index'], ['test-rule']); + + expect(clusterClient.updateByQuery).toHaveBeenCalledTimes(1); + }); + + test('should retry updateByQuery on failure', async () => { + clusterClient.updateByQuery.mockResponseOnce({ + total: 10, + updated: 8, + }); + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>( + alertsClientParams + ); + + const opts = { + maxAlerts, + ruleLabel: `test: rule-name`, + flappingSettings: DEFAULT_FLAPPING_SETTINGS, + activeAlertsFromState: {}, + recoveredAlertsFromState: {}, + }; + await alertsClient.initializeExecution(opts); + + await alertsClient.setAlertStatusToUntracked(['test-index'], ['test-rule']); + + expect(clusterClient.updateByQuery).toHaveBeenCalledTimes(2); + expect(logger.warn).toHaveBeenCalledWith( + 'Attempt 1: Failed to untrack 2 of 10; indices test-index, ruleIds test-rule' + ); + }); + }); }); } }); diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts index 1f790ae1f7cabd..8164989761af7f 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts @@ -6,7 +6,13 @@ */ import { ElasticsearchClient } from '@kbn/core/server'; -import { ALERT_RULE_UUID, ALERT_UUID } from '@kbn/rule-data-utils'; +import { + ALERT_RULE_UUID, + ALERT_STATUS, + ALERT_STATUS_UNTRACKED, + ALERT_STATUS_ACTIVE, + ALERT_UUID, +} from '@kbn/rule-data-utils'; import { chunk, flatMap, isEmpty, keys } from 'lodash'; import { SearchRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { Alert } from '@kbn/alerts-as-data-utils'; @@ -198,6 +204,51 @@ export class AlertsClient< return { hits, total }; } + public async setAlertStatusToUntracked(indices: string[], ruleIds: string[]) { + const esClient = await this.options.elasticsearchClientPromise; + const terms: Array<{ term: Record }> = ruleIds.map((ruleId) => ({ + term: { + [ALERT_RULE_UUID]: { value: ruleId }, + }, + })); + terms.push({ + term: { + [ALERT_STATUS]: { value: ALERT_STATUS_ACTIVE }, + }, + }); + + try { + // Retry this updateByQuery up to 3 times to make sure the number of documents + // updated equals the number of documents matched + for (let retryCount = 0; retryCount < 3; retryCount++) { + const response = await esClient.updateByQuery({ + index: indices, + allow_no_indices: true, + body: { + conflicts: 'proceed', + script: { + source: UNTRACK_UPDATE_PAINLESS_SCRIPT, + lang: 'painless', + }, + query: { + bool: { + must: terms, + }, + }, + }, + }); + if (response.total === response.updated) break; + this.options.logger.warn( + `Attempt ${retryCount + 1}: Failed to untrack ${ + (response.total ?? 0) - (response.updated ?? 0) + } of ${response.total}; indices ${indices}, ruleIds ${ruleIds}` + ); + } + } catch (err) { + this.options.logger.error(`Error marking ${ruleIds} as untracked - ${err.message}`); + } + } + public report( alert: ReportedAlert< AlertData, @@ -562,3 +613,11 @@ export class AlertsClient< return this._isUsingDataStreams; } } + +const UNTRACK_UPDATE_PAINLESS_SCRIPT = ` +// Certain rule types don't flatten their AAD values, apply the ALERT_STATUS key to them directly +if (!ctx._source.containsKey('${ALERT_STATUS}') || ctx._source['${ALERT_STATUS}'].empty) { + ctx._source.${ALERT_STATUS} = '${ALERT_STATUS_UNTRACKED}'; +} else { + ctx._source['${ALERT_STATUS}'] = '${ALERT_STATUS_UNTRACKED}' +}`; diff --git a/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.ts index b7c17ee9579a83..26f7171a396861 100644 --- a/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.ts @@ -232,4 +232,8 @@ export class LegacyAlertsClient< } public async persistAlerts() {} + + public async setAlertStatusToUntracked() { + return; + } } diff --git a/x-pack/plugins/alerting/server/alerts_client/types.ts b/x-pack/plugins/alerting/server/alerts_client/types.ts index eccd381bc2a5cc..94adde28926236 100644 --- a/x-pack/plugins/alerting/server/alerts_client/types.ts +++ b/x-pack/plugins/alerting/server/alerts_client/types.ts @@ -63,6 +63,7 @@ export interface IAlertsClient< alertsToReturn: Record; recoveredAlertsToReturn: Record; }; + setAlertStatusToUntracked(indices: string[], ruleIds: string[]): Promise; factory(): PublicAlertFactory< State, Context, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts index 9bdac512cd28cf..fd9daa3cb7356a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts @@ -56,6 +56,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, maxScheduledPerMinute: 1000, internalSavedObjectsRepository, }; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts index c33cd867a1be8b..611aca68c81c3b 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts @@ -79,6 +79,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; const getBulkOperationStatusErrorResponse = (statusCode: number) => ({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts index 1a2faed2e0e661..e5d7e0c8db43a9 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts @@ -102,6 +102,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: isAuthenticationTypeApiKeyMock, getAuthenticationAPIKey: getAuthenticationApiKeyMock, + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; const paramsModifier = jest.fn(); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts index 2d7746f715a05e..41ca041e89a0b4 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts @@ -82,6 +82,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts index cbd1476e111a12..d23e4b3a7dd545 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts @@ -53,6 +53,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; const getMockAggregationResult = ( diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts index 45f8d84fd4a98a..a4bdc2f88bfa04 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts @@ -127,6 +127,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": true, "status": "OK", + "tracked": true, "uuid": undefined, }, "alert-2": Object { @@ -135,6 +136,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": true, "status": "OK", + "tracked": true, "uuid": undefined, }, }, @@ -241,6 +243,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "OK", + "tracked": true, "uuid": "uuid-1", }, }, @@ -283,6 +286,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "OK", + "tracked": true, "uuid": "uuid-1", }, }, @@ -324,6 +328,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "OK", + "tracked": true, "uuid": "uuid-1", }, }, @@ -366,6 +371,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, }, @@ -408,6 +414,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, }, @@ -450,6 +457,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, }, @@ -490,6 +498,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, }, @@ -534,6 +543,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": true, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, "alert-2": Object { @@ -542,6 +552,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": true, "status": "OK", + "tracked": true, "uuid": "uuid-2", }, }, @@ -593,6 +604,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, "alert-2": Object { @@ -601,6 +613,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": false, "muted": false, "status": "OK", + "tracked": true, "uuid": "uuid-2", }, }, @@ -639,6 +652,7 @@ describe('alertSummaryFromEventLog', () => { "flapping": true, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, }, diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts index d316b1b5bf01ce..e20b92370bbc67 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts @@ -105,6 +105,8 @@ export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams) status.activeStartDate = undefined; status.actionGroupId = undefined; } + + status.tracked = action !== EVENT_LOG_ACTIONS.untrackedInstance; } for (const event of executionEvents.reverse()) { @@ -169,6 +171,7 @@ function getAlertStatus( actionGroupId: undefined, activeStartDate: undefined, flapping: false, + tracked: true, }; alerts.set(alertId, status); return status; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index e2e98347d88fec..e9590f883cc53d 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -111,6 +111,7 @@ export const EVENT_LOG_ACTIONS = { recoveredInstance: 'recovered-instance', activeInstance: 'active-instance', executeTimeout: 'execute-timeout', + untrackedInstance: 'untracked-instance', }; export const LEGACY_EVENT_LOG_ACTIONS = { resolvedInstance: 'resolved-instance', @@ -494,6 +495,8 @@ export class AlertingPlugin { eventLogger: this.eventLogger, minimumScheduleInterval: this.config.rules.minimumScheduleInterval, maxScheduledPerMinute: this.config.rules.maxScheduledPerMinute, + getAlertIndicesAlias: createGetAlertIndicesAliasFn(this.ruleTypeRegistry!), + alertsService: this.alertsService, }); rulesSettingsClientFactory.initialize({ diff --git a/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts index 0548c5f7fc7836..ae5bf3f759194c 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts @@ -52,6 +52,8 @@ const rulesClientParams: jest.Mocked = { fieldsToExcludeFromPublicApi: [], isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; const username = 'test'; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/index.ts b/x-pack/plugins/alerting/server/rules_client/lib/index.ts index 0dcaa31fe51a11..ab1f33df01c107 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/index.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/index.ts @@ -14,7 +14,7 @@ export { getAuthorizationFilter } from './get_authorization_filter'; export { checkAuthorizationAndGetTotal } from './check_authorization_and_get_total'; export { scheduleTask } from './schedule_task'; export { createNewAPIKeySet } from './create_new_api_key_set'; -export { recoverRuleAlerts } from './recover_rule_alerts'; +export { untrackRuleAlerts } from './untrack_rule_alerts'; export { migrateLegacyActions } from './siem_legacy_actions/migrate_legacy_actions'; export { formatLegacyActions } from './siem_legacy_actions/format_legacy_actions'; export { addGeneratedActionValues } from './add_generated_action_values'; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/recover_rule_alerts.ts b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts similarity index 51% rename from x-pack/plugins/alerting/server/rules_client/lib/recover_rule_alerts.ts rename to x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts index 9648f23dc05d2b..7eaee0e468e1cf 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/recover_rule_alerts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts @@ -15,40 +15,50 @@ import { EVENT_LOG_ACTIONS } from '../../plugin'; import { createAlertEventLogRecordObject } from '../../lib/create_alert_event_log_record_object'; import { RulesClientContext } from '../types'; -export const recoverRuleAlerts = async ( +export const untrackRuleAlerts = async ( context: RulesClientContext, id: string, attributes: RawRule ) => { - return withSpan({ name: 'recoverRuleAlerts', type: 'rules' }, async () => { + return withSpan({ name: 'untrackRuleAlerts', type: 'rules' }, async () => { if (!context.eventLogger || !attributes.scheduledTaskId) return; try { - const { state } = taskInstanceToAlertTaskInstance( + const taskInstance = taskInstanceToAlertTaskInstance( await context.taskManager.get(attributes.scheduledTaskId), attributes as unknown as SanitizedRule ); - const recoveredAlerts = mapValues, Alert>( + const { state } = taskInstance; + + const untrackedAlerts = mapValues, Alert>( state.alertInstances ?? {}, (rawAlertInstance, alertId) => new Alert(alertId, rawAlertInstance) ); - const recoveredAlertIds = Object.keys(recoveredAlerts); - for (const alertId of recoveredAlertIds) { - const { group: actionGroup } = recoveredAlerts[alertId].getLastScheduledActions() ?? {}; - const instanceState = recoveredAlerts[alertId].getState(); - const message = `instance '${alertId}' has recovered due to the rule was disabled`; - const alertUuid = recoveredAlerts[alertId].getUuid(); + const untrackedAlertIds = Object.keys(untrackedAlerts); + + const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId); + + const { autoRecoverAlerts: isLifecycleAlert } = ruleType; + + // Untrack Stack alerts + // TODO: Replace this loop with an Alerts As Data implmentation when Stack Rules use Alerts As Data + // instead of the Kibana Event Log + for (const alertId of untrackedAlertIds) { + const { group: actionGroup } = untrackedAlerts[alertId].getLastScheduledActions() ?? {}; + const instanceState = untrackedAlerts[alertId].getState(); + const message = `instance '${alertId}' has been untracked because the rule was disabled`; + const alertUuid = untrackedAlerts[alertId].getUuid(); const event = createAlertEventLogRecordObject({ ruleId: id, ruleName: attributes.name, ruleRevision: attributes.revision, - ruleType: context.ruleTypeRegistry.get(attributes.alertTypeId), + ruleType, consumer: attributes.consumer, instanceId: alertId, alertUuid, - action: EVENT_LOG_ACTIONS.recoveredInstance, + action: EVENT_LOG_ACTIONS.untrackedInstance, message, state: instanceState, group: actionGroup, @@ -65,10 +75,32 @@ export const recoverRuleAlerts = async ( }); context.eventLogger.logEvent(event); } + + // Untrack Lifecycle alerts (Alerts As Data-enabled) + if (isLifecycleAlert) { + const alertsClient = await context.alertsService?.createAlertsClient({ + namespace: context.namespace!, + rule: { + id, + name: attributes.name, + consumer: attributes.consumer, + revision: attributes.revision, + spaceId: context.spaceId, + tags: attributes.tags, + parameters: attributes.parameters, + executionId: '', + }, + ruleType, + logger: context.logger, + }); + if (!alertsClient) throw new Error('Could not create alertsClient'); + const indices = context.getAlertIndicesAlias([ruleType.id], context.spaceId); + await alertsClient.setAlertStatusToUntracked(indices, [id]); + } } catch (error) { // this should not block the rest of the disable process context.logger.warn( - `rulesClient.disable('${id}') - Could not write recovery events - ${error.message}` + `rulesClient.disable('${id}') - Could not write untrack events - ${error.message}` ); } }); diff --git a/x-pack/plugins/alerting/server/rules_client/methods/bulk_disable.ts b/x-pack/plugins/alerting/server/rules_client/methods/bulk_disable.ts index 30b8b1eb01bba4..d409d69f8a6ac9 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/bulk_disable.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/bulk_disable.ts @@ -22,7 +22,7 @@ import { getAuthorizationFilter, checkAuthorizationAndGetTotal, getAlertFromRaw, - recoverRuleAlerts, + untrackRuleAlerts, updateMeta, migrateLegacyActions, } from '../lib'; @@ -58,11 +58,12 @@ export const bulkDisableRules = async (context: RulesClientContext, options: Bul }) ); - const [taskIdsToDisable, taskIdsToDelete] = accListSpecificForBulkOperation; + const [taskIdsToDisable, taskIdsToDelete, taskIdsToClearState] = accListSpecificForBulkOperation; await Promise.allSettled([ tryToDisableTasks({ taskIdsToDisable, + taskIdsToClearState, logger: context.logger, taskManager: context.taskManager, }), @@ -114,7 +115,7 @@ const bulkDisableRulesWithOCC = async ( for await (const response of rulesFinder.find()) { await pMap(response.saved_objects, async (rule) => { try { - await recoverRuleAlerts(context, rule.id, rule.attributes); + await untrackRuleAlerts(context, rule.id, rule.attributes); if (rule.attributes.name) { ruleNameToRuleIdMapping[rule.id] = rule.attributes.name; @@ -193,6 +194,7 @@ const bulkDisableRulesWithOCC = async ( const taskIdsToDisable: string[] = []; const taskIdsToDelete: string[] = []; + const taskIdsToClearState: string[] = []; const disabledRules: Array> = []; result.saved_objects.forEach((rule) => { @@ -202,6 +204,12 @@ const bulkDisableRulesWithOCC = async ( taskIdsToDelete.push(rule.attributes.scheduledTaskId); } else { taskIdsToDisable.push(rule.attributes.scheduledTaskId); + if (rule.attributes.alertTypeId) { + const { autoRecoverAlerts: isLifecycleAlert } = context.ruleTypeRegistry.get( + rule.attributes.alertTypeId + ); + if (isLifecycleAlert) taskIdsToClearState.push(rule.attributes.scheduledTaskId); + } } } disabledRules.push(rule); @@ -221,23 +229,28 @@ const bulkDisableRulesWithOCC = async ( errors, // TODO: delete the casting when we do versioning of bulk disable api rules: disabledRules as Array>, - accListSpecificForBulkOperation: [taskIdsToDisable, taskIdsToDelete], + accListSpecificForBulkOperation: [taskIdsToDisable, taskIdsToDelete, taskIdsToClearState], }; }; const tryToDisableTasks = async ({ taskIdsToDisable, + taskIdsToClearState, logger, taskManager, }: { taskIdsToDisable: string[]; + taskIdsToClearState: string[]; logger: Logger; taskManager: TaskManagerStartContract; }) => { return await withSpan({ name: 'taskManager.bulkDisable', type: 'rules' }, async () => { if (taskIdsToDisable.length > 0) { try { - const resultFromDisablingTasks = await taskManager.bulkDisable(taskIdsToDisable); + const resultFromDisablingTasks = await taskManager.bulkDisable( + taskIdsToDisable, + taskIdsToClearState + ); if (resultFromDisablingTasks.tasks.length) { logger.debug( `Successfully disabled schedules for underlying tasks: ${resultFromDisablingTasks.tasks diff --git a/x-pack/plugins/alerting/server/rules_client/methods/disable.ts b/x-pack/plugins/alerting/server/rules_client/methods/disable.ts index 1382b7d14b1119..88ffd510e8800a 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/disable.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/disable.ts @@ -11,7 +11,7 @@ import { WriteOperations, AlertingAuthorizationEntity } from '../../authorizatio import { retryIfConflicts } from '../../lib/retry_if_conflicts'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; -import { recoverRuleAlerts, updateMeta, migrateLegacyActions } from '../lib'; +import { untrackRuleAlerts, updateMeta, migrateLegacyActions } from '../lib'; export async function disable(context: RulesClientContext, { id }: { id: string }): Promise { return await retryIfConflicts( @@ -43,7 +43,7 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string references = alert.references; } - await recoverRuleAlerts(context, id, attributes); + await untrackRuleAlerts(context, id, attributes); try { await context.authorization.ensureAuthorized({ @@ -102,6 +102,9 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string : {}), } ); + const { autoRecoverAlerts: isLifecycleAlert } = context.ruleTypeRegistry.get( + attributes.alertTypeId + ); // If the scheduledTaskId does not match the rule id, we should // remove the task, otherwise mark the task as disabled @@ -109,7 +112,10 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string if (attributes.scheduledTaskId !== id) { await context.taskManager.removeIfExists(attributes.scheduledTaskId); } else { - await context.taskManager.bulkDisable([attributes.scheduledTaskId]); + await context.taskManager.bulkDisable( + [attributes.scheduledTaskId], + Boolean(isLifecycleAlert) + ); } } } diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts index c4d7e6eb4f7550..966a87c695d103 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts @@ -87,6 +87,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { @@ -251,7 +253,7 @@ describe('bulkDisableRules', () => { expect(unsecuredSavedObjectsClient.bulkCreate).toHaveBeenCalledTimes(4); expect(taskManager.bulkDisable).toHaveBeenCalledTimes(1); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1'], []); expect(result).toStrictEqual({ errors: [{ message: 'UPS', rule: { id: 'id2', name: 'fakeName' }, status: 409 }], rules: [returnedDisabledRule1], @@ -388,7 +390,7 @@ describe('bulkDisableRules', () => { await rulesClient.bulkDisableRules({ filter: 'fake_filter' }); expect(taskManager.bulkDisable).toHaveBeenCalledTimes(1); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1', 'id2']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1', 'id2'], []); expect(logger.debug).toBeCalledTimes(1); expect(logger.debug).toBeCalledWith( @@ -451,7 +453,7 @@ describe('bulkDisableRules', () => { await rulesClient.bulkDisableRules({ filter: 'fake_filter' }); expect(taskManager.bulkDisable).toHaveBeenCalledTimes(1); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1'], []); expect(logger.debug).toBeCalledTimes(1); expect(logger.debug).toBeCalledWith( @@ -477,7 +479,7 @@ describe('bulkDisableRules', () => { await rulesClient.bulkDisableRules({ filter: 'fake_filter' }); expect(taskManager.bulkDisable).toHaveBeenCalledTimes(1); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['id1'], []); }); test('should not throw an error if taskManager.bulkDisable throw an error', async () => { @@ -611,7 +613,7 @@ describe('bulkDisableRules', () => { expect(logger.warn).toHaveBeenCalledTimes(2); expect(logger.warn).toHaveBeenLastCalledWith( - "rulesClient.disable('id2') - Could not write recovery events - UPS" + "rulesClient.disable('id2') - Could not write untrack events - UPS" ); }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts index acba28bf20ac6c..af03c5908daff7 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts @@ -82,6 +82,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts index efebe91a90272b..b64f1920455119 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts @@ -69,6 +69,8 @@ const rulesClientParams: jest.Mocked = { eventLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; describe('clearExpiredSnoozes()', () => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts index ece860c63c30e7..a4e581414744a4 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts @@ -71,6 +71,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts index 23b23b607cd045..ca6c242539a9ae 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts @@ -73,6 +73,8 @@ const rulesClientParams: jest.Mocked = { eventLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { @@ -255,11 +257,11 @@ describe('disable()', () => { version: '123', } ); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1'], false); expect(taskManager.removeIfExists).not.toHaveBeenCalledWith(); }); - test('disables the rule with calling event log to "recover" the alert instances from the task state', async () => { + test('disables the rule with calling event log to untrack the alert instances from the task state', async () => { const scheduledTaskId = '1'; taskManager.get.mockResolvedValue({ id: scheduledTaskId, @@ -329,13 +331,13 @@ describe('disable()', () => { version: '123', } ); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1'], false); expect(taskManager.removeIfExists).not.toHaveBeenCalledWith(); expect(eventLogger.logEvent).toHaveBeenCalledTimes(1); expect(eventLogger.logEvent.mock.calls[0][0]).toStrictEqual({ event: { - action: 'recovered-instance', + action: 'untracked-instance', category: ['alerts'], kind: 'alert', }, @@ -363,7 +365,7 @@ describe('disable()', () => { ], space_ids: ['default'], }, - message: "instance '1' has recovered due to the rule was disabled", + message: "instance '1' has been untracked because the rule was disabled", rule: { category: '123', id: '1', @@ -373,7 +375,7 @@ describe('disable()', () => { }); }); - test('disables the rule even if unable to retrieve task manager doc to generate recovery event log events', async () => { + test('disables the rule even if unable to retrieve task manager doc to generate untrack event log events', async () => { taskManager.get.mockRejectedValueOnce(new Error('Fail')); await rulesClient.disable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); @@ -414,12 +416,12 @@ describe('disable()', () => { version: '123', } ); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1'], false); expect(taskManager.removeIfExists).not.toHaveBeenCalledWith(); expect(eventLogger.logEvent).toHaveBeenCalledTimes(0); expect(rulesClientParams.logger.warn).toHaveBeenCalledWith( - `rulesClient.disable('1') - Could not write recovery events - Fail` + `rulesClient.disable('1') - Could not write untrack events - Fail` ); }); @@ -459,7 +461,7 @@ describe('disable()', () => { version: '123', } ); - expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1']); + expect(taskManager.bulkDisable).toHaveBeenCalledWith(['1'], false); expect(taskManager.removeIfExists).not.toHaveBeenCalledWith(); }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts index e7e09c55a79202..9ab3a919f01a59 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts @@ -70,6 +70,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; setGlobalDate(); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts index 3d697b08dc2f19..e7e737b635f28f 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts @@ -63,6 +63,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts index 36a5510a03a3b4..5e98fcfee37219 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts @@ -60,6 +60,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts index d8069721c4a5c9..0fe46a07e4e7f8 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts @@ -59,6 +59,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts index 644cc6190f6054..dee5cb2ab9a81a 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts @@ -51,6 +51,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts index 68160306d34247..1521dfdefced36 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts @@ -57,6 +57,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { @@ -170,6 +172,7 @@ describe('getAlertSummary()', () => { "flapping": true, "muted": false, "status": "Active", + "tracked": true, "uuid": "uuid-1", }, "alert-muted-no-activity": Object { @@ -178,6 +181,7 @@ describe('getAlertSummary()', () => { "flapping": false, "muted": true, "status": "OK", + "tracked": true, "uuid": undefined, }, "alert-previously-active": Object { @@ -186,6 +190,7 @@ describe('getAlertSummary()', () => { "flapping": false, "muted": false, "status": "OK", + "tracked": true, "uuid": "uuid-2", }, }, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts index 0704a0e7afe16e..f1d2dbcacf8fda 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts @@ -60,6 +60,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_tags.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_tags.test.ts index 6d55fe7f407255..54971f47a3b09d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_tags.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_tags.test.ts @@ -54,6 +54,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; const listedTypes = new Set([ diff --git a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts index 09aed8b28bfb45..0b95247b60adfb 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts @@ -55,6 +55,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts index 7466d7405fa246..2b6e2793aa648d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts @@ -51,6 +51,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts index 2dedc7f92f38d5..4d7f1a52699cc3 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts @@ -51,6 +51,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts index 5dc753f5d4ade8..dd3ccaea5b67c6 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts @@ -60,6 +60,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts index 20bbd2fb72f1a5..9040096eba8b0b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts @@ -53,6 +53,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; setGlobalDate(); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts index ecdea250916bea..c8cb134b129d71 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts @@ -51,6 +51,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts index 4b030bb7eb2b59..4df037b8728f0d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts @@ -51,6 +51,8 @@ const rulesClientParams: jest.Mocked = { kibanaVersion, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts index cd97ea0ac1bbd7..8b275d12cfa0a9 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts @@ -90,6 +90,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts index cc5d4e32511bcc..f9cd570afa430e 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts @@ -58,6 +58,8 @@ const rulesClientParams: jest.Mocked = { auditLogger, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/types.ts b/x-pack/plugins/alerting/server/rules_client/types.ts index 87ae5949762468..7428f81529f20a 100644 --- a/x-pack/plugins/alerting/server/rules_client/types.ts +++ b/x-pack/plugins/alerting/server/rules_client/types.ts @@ -32,6 +32,8 @@ import { } from '../types'; import { AlertingAuthorization } from '../authorization'; import { AlertingRulesConfig } from '../config'; +import { GetAlertIndicesAlias } from '../lib'; +import { AlertsService } from '../alerts_service'; export type { BulkEditOperation, @@ -74,6 +76,8 @@ export interface RulesClientContext { readonly fieldsToExcludeFromPublicApi: Array; readonly isAuthenticationTypeAPIKey: () => boolean; readonly getAuthenticationAPIKey: (name: string) => CreateAPIKeyResult; + readonly getAlertIndicesAlias: GetAlertIndicesAlias; + readonly alertsService: AlertsService | null; } export type NormalizedAlertAction = Omit; diff --git a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts index c2c1f73bbe5fb6..036fa1c98ff8fa 100644 --- a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts @@ -66,6 +66,8 @@ const rulesClientParams: jest.Mocked = { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: jest.fn(), getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, }; // this suite consists of two suites running tests against mutable RulesClient APIs: diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 6bb4f945d54303..9f1a4acb12420b 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -46,6 +46,8 @@ const rulesClientFactoryParams: jest.Mocked = { ruleTypeRegistry: ruleTypeRegistryMock.create(), getSpaceId: jest.fn(), spaceIdToNamespace: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, maxScheduledPerMinute: 10000, minimumScheduleInterval: { value: '1m', enforce: false }, internalSavedObjectsRepository, @@ -112,6 +114,8 @@ test('creates a rules client with proper constructor arguments when security is minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: expect.any(Function), getAuthenticationAPIKey: expect.any(Function), + getAlertIndicesAlias: expect.any(Function), + alertsService: null, }); }); @@ -154,6 +158,8 @@ test('creates a rules client with proper constructor arguments', async () => { minimumScheduleInterval: { value: '1m', enforce: false }, isAuthenticationTypeAPIKey: expect.any(Function), getAuthenticationAPIKey: expect.any(Function), + getAlertIndicesAlias: expect.any(Function), + alertsService: null, }); }); diff --git a/x-pack/plugins/alerting/server/rules_client_factory.ts b/x-pack/plugins/alerting/server/rules_client_factory.ts index e0b9de5dc53e2e..6f2930429256eb 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.ts @@ -26,6 +26,8 @@ import { RuleTypeRegistry, SpaceIdToNamespaceFunction } from './types'; import { RulesClient } from './rules_client'; import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory'; import { AlertingRulesConfig } from './config'; +import { GetAlertIndicesAlias } from './lib'; +import { AlertsService } from './alerts_service/alerts_service'; export interface RulesClientFactoryOpts { logger: Logger; taskManager: TaskManagerStartContract; @@ -43,6 +45,8 @@ export interface RulesClientFactoryOpts { eventLogger?: IEventLogger; minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval']; maxScheduledPerMinute: AlertingRulesConfig['maxScheduledPerMinute']; + getAlertIndicesAlias: GetAlertIndicesAlias; + alertsService: AlertsService | null; } export class RulesClientFactory { @@ -63,6 +67,8 @@ export class RulesClientFactory { private eventLogger?: IEventLogger; private minimumScheduleInterval!: AlertingRulesConfig['minimumScheduleInterval']; private maxScheduledPerMinute!: AlertingRulesConfig['maxScheduledPerMinute']; + private getAlertIndicesAlias!: GetAlertIndicesAlias; + private alertsService!: AlertsService | null; public initialize(options: RulesClientFactoryOpts) { if (this.isInitialized) { @@ -85,6 +91,8 @@ export class RulesClientFactory { this.eventLogger = options.eventLogger; this.minimumScheduleInterval = options.minimumScheduleInterval; this.maxScheduledPerMinute = options.maxScheduledPerMinute; + this.getAlertIndicesAlias = options.getAlertIndicesAlias; + this.alertsService = options.alertsService; } public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient { @@ -113,6 +121,8 @@ export class RulesClientFactory { internalSavedObjectsRepository: this.internalSavedObjectsRepository, encryptedSavedObjectsClient: this.encryptedSavedObjectsClient, auditLogger: securityPluginSetup?.audit.asScoped(request), + getAlertIndicesAlias: this.getAlertIndicesAlias, + alertsService: this.alertsService, async getUserName() { if (!securityPluginStart) { return null; diff --git a/x-pack/plugins/infra/public/common/alerts/constants.ts b/x-pack/plugins/infra/public/common/alerts/constants.ts index 8c71ba66e86e8b..950825f5112867 100644 --- a/x-pack/plugins/infra/public/common/alerts/constants.ts +++ b/x-pack/plugins/infra/public/common/alerts/constants.ts @@ -6,7 +6,12 @@ */ import { i18n } from '@kbn/i18n'; -import { ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; +import { + ALERT_STATUS, + ALERT_STATUS_ACTIVE, + ALERT_STATUS_RECOVERED, + ALERT_STATUS_UNTRACKED, +} from '@kbn/rule-data-utils'; import type { AlertStatusFilter } from './types'; export const ALERT_STATUS_ALL = 'all'; @@ -46,9 +51,24 @@ export const RECOVERED_ALERTS: AlertStatusFilter = { }), }; +export const UNTRACKED_ALERTS: AlertStatusFilter = { + status: ALERT_STATUS_UNTRACKED, + query: { + term: { + [ALERT_STATUS]: { + value: ALERT_STATUS_UNTRACKED, + }, + }, + }, + label: i18n.translate('xpack.infra.hostsViewPage.tabs.alerts.alertStatusFilter.untracked', { + defaultMessage: 'Untracked', + }), +}; + export const ALERT_STATUS_QUERY = { [ACTIVE_ALERTS.status]: ACTIVE_ALERTS.query, [RECOVERED_ALERTS.status]: RECOVERED_ALERTS.query, + [UNTRACKED_ALERTS.status]: UNTRACKED_ALERTS.query, }; export const ALERTS_DOC_HREF = diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_status_filter.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_status_filter.tsx index 9298b2e420642c..255273b5cd5136 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_status_filter.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_status_filter.tsx @@ -13,6 +13,7 @@ import { ACTIVE_ALERTS, ALL_ALERTS, RECOVERED_ALERTS, + UNTRACKED_ALERTS, } from '../../../../../../common/alerts/constants'; export interface AlertStatusFilterProps { status: AlertStatus; @@ -38,6 +39,12 @@ const options: EuiButtonGroupOptionProps[] = [ value: RECOVERED_ALERTS.query, 'data-test-subj': 'hostsView-alert-status-filter-recovered-button', }, + { + id: UNTRACKED_ALERTS.status, + label: UNTRACKED_ALERTS.label, + value: UNTRACKED_ALERTS.query, + 'data-test-subj': 'hostsView-alert-status-filter-untracked-button', + }, ]; export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) { diff --git a/x-pack/plugins/observability/common/typings.ts b/x-pack/plugins/observability/common/typings.ts index ce2fdb7460688c..dfddf89992c19b 100644 --- a/x-pack/plugins/observability/common/typings.ts +++ b/x-pack/plugins/observability/common/typings.ts @@ -6,7 +6,11 @@ */ import * as t from 'io-ts'; -import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; +import { + ALERT_STATUS_ACTIVE, + ALERT_STATUS_RECOVERED, + ALERT_STATUS_UNTRACKED, +} from '@kbn/rule-data-utils'; import { ALERT_STATUS_ALL } from './constants'; export type Maybe = T | null | undefined; @@ -29,6 +33,7 @@ export interface ApmIndicesConfig { export type AlertStatus = | typeof ALERT_STATUS_ACTIVE | typeof ALERT_STATUS_RECOVERED + | typeof ALERT_STATUS_UNTRACKED | typeof ALERT_STATUS_ALL; export interface AlertStatusFilter { diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/components/alerts_status_filter.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/components/alerts_status_filter.tsx index 73cdfeceade3e5..dbfca389e0bccb 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/components/alerts_status_filter.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/components/alerts_status_filter.tsx @@ -8,7 +8,7 @@ import { EuiButtonGroup, EuiButtonGroupOptionProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { ALL_ALERTS, ACTIVE_ALERTS, RECOVERED_ALERTS } from '../constants'; +import { ALL_ALERTS, ACTIVE_ALERTS, RECOVERED_ALERTS, UNTRACKED_ALERTS } from '../constants'; import { AlertStatusFilterProps } from '../types'; import { AlertStatus } from '../../../../common/typings'; @@ -31,6 +31,12 @@ const options: EuiButtonGroupOptionProps[] = [ value: RECOVERED_ALERTS.query, 'data-test-subj': 'alert-status-filter-recovered-button', }, + { + id: UNTRACKED_ALERTS.status, + label: UNTRACKED_ALERTS.label, + value: UNTRACKED_ALERTS.query, + 'data-test-subj': 'alert-status-filter-untracked-button', + }, ]; export function AlertsStatusFilter({ status, onChange }: AlertStatusFilterProps) { diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/constants.ts b/x-pack/plugins/observability/public/components/alert_search_bar/constants.ts index c067baafe28f15..85ea6464d5ac0e 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/constants.ts +++ b/x-pack/plugins/observability/public/components/alert_search_bar/constants.ts @@ -7,7 +7,12 @@ import { Query } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; -import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, ALERT_STATUS } from '@kbn/rule-data-utils'; +import { + ALERT_STATUS_ACTIVE, + ALERT_STATUS_RECOVERED, + ALERT_STATUS_UNTRACKED, + ALERT_STATUS, +} from '@kbn/rule-data-utils'; import { AlertStatusFilter } from '../../../common/typings'; import { ALERT_STATUS_ALL } from '../../../common/constants'; @@ -38,7 +43,16 @@ export const RECOVERED_ALERTS: AlertStatusFilter = { }), }; +export const UNTRACKED_ALERTS: AlertStatusFilter = { + status: ALERT_STATUS_UNTRACKED, + query: `${ALERT_STATUS}: "${ALERT_STATUS_UNTRACKED}"`, + label: i18n.translate('xpack.observability.alerts.alertStatusFilter.untracked', { + defaultMessage: 'Untracked', + }), +}; + export const ALERT_STATUS_QUERY = { [ACTIVE_ALERTS.status]: ACTIVE_ALERTS.query, [RECOVERED_ALERTS.status]: RECOVERED_ALERTS.query, + [UNTRACKED_ALERTS.status]: UNTRACKED_ALERTS.query, }; diff --git a/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_body.tsx b/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_body.tsx index 297ee793289f40..735d38d0604d0f 100644 --- a/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_body.tsx +++ b/x-pack/plugins/observability/public/components/alerts_flyout/alerts_flyout_body.tsx @@ -16,6 +16,7 @@ import { EuiFlyoutBody, } from '@elastic/eui'; import { + AlertStatus, ALERT_DURATION, ALERT_EVALUATION_THRESHOLD, ALERT_EVALUATION_VALUE, @@ -23,8 +24,7 @@ import { ALERT_RULE_CATEGORY, ALERT_RULE_TYPE_ID, ALERT_RULE_UUID, - ALERT_STATUS_ACTIVE, - ALERT_STATUS_RECOVERED, + ALERT_STATUS, } from '@kbn/rule-data-utils'; import { i18n } from '@kbn/i18n'; import { AlertLifecycleStatusBadge } from '@kbn/alerts-ui-shared'; @@ -64,7 +64,7 @@ export function AlertsFlyoutBody({ alert, id: pageId }: FlyoutProps) { }), description: ( ), diff --git a/x-pack/plugins/task_manager/server/task_scheduling.ts b/x-pack/plugins/task_manager/server/task_scheduling.ts index 85c346d52da05f..5ee848c716bec3 100644 --- a/x-pack/plugins/task_manager/server/task_scheduling.ts +++ b/x-pack/plugins/task_manager/server/task_scheduling.ts @@ -152,13 +152,20 @@ export class TaskScheduling { return await this.store.bulkSchedule(modifiedTasks); } - public async bulkDisable(taskIds: string[]) { + public async bulkDisable(taskIds: string[], clearStateIdsOrBoolean?: string[] | boolean) { return await retryableBulkUpdate({ taskIds, store: this.store, getTasks: async (ids) => await this.bulkGetTasksHelper(ids), filter: (task) => !!task.enabled, - map: (task) => ({ ...task, enabled: false }), + map: (task) => ({ + ...task, + enabled: false, + ...((Array.isArray(clearStateIdsOrBoolean) && clearStateIdsOrBoolean.includes(task.id)) || + clearStateIdsOrBoolean === true + ? { state: {} } + : {}), + }), validate: false, }); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_summary.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_summary.test.ts index 889f2634eacc92..19455dc9e9c588 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_summary.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_summary.test.ts @@ -19,6 +19,7 @@ describe('loadRuleSummary', () => { flapping: true, status: 'OK', muted: false, + tracked: true, }, }, consumer: 'alerts', @@ -47,6 +48,7 @@ describe('loadRuleSummary', () => { flapping: true, status: 'OK', muted: false, + tracked: true, }, }, consumer: 'alerts', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx index 7f49f8872f109b..fd0d18552191c5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx @@ -128,12 +128,14 @@ describe('rules', () => { muted: false, actionGroupId: 'default', flapping: false, + tracked: true, }, second_rule: { status: 'Active', muted: false, actionGroupId: 'action group id unknown', flapping: false, + tracked: true, }, }, }); @@ -192,11 +194,13 @@ describe('rules', () => { status: 'OK', muted: false, flapping: false, + tracked: true, }, ['us-east']: { status: 'OK', muted: false, flapping: false, + tracked: true, }, }; @@ -228,8 +232,8 @@ describe('rules', () => { mutedInstanceIds: ['us-west', 'us-east'], }); const ruleType = mockRuleType(); - const ruleUsWest: AlertStatus = { status: 'OK', muted: false, flapping: false }; - const ruleUsEast: AlertStatus = { status: 'OK', muted: false, flapping: false }; + const ruleUsWest: AlertStatus = { status: 'OK', muted: false, flapping: false, tracked: true }; + const ruleUsEast: AlertStatus = { status: 'OK', muted: false, flapping: false, tracked: true }; const wrapper = mountWithIntl( { status: 'OK', muted: false, flapping: false, + tracked: true, }, 'us-east': { status: 'OK', muted: false, flapping: false, + tracked: true, }, }, })} @@ -275,6 +281,7 @@ describe('alertToListItem', () => { activeStartDate: fake2MinutesAgo.toISOString(), actionGroupId: 'testing', flapping: false, + tracked: true, }; expect(alertToListItem(fakeNow.getTime(), 'id', alert)).toEqual({ @@ -285,6 +292,7 @@ describe('alertToListItem', () => { sortPriority: 0, duration: fakeNow.getTime() - fake2MinutesAgo.getTime(), isMuted: false, + tracked: true, }); }); @@ -295,6 +303,7 @@ describe('alertToListItem', () => { muted: false, activeStartDate: fake2MinutesAgo.toISOString(), flapping: false, + tracked: true, }; expect(alertToListItem(fakeNow.getTime(), 'id', alert)).toEqual({ @@ -305,6 +314,7 @@ describe('alertToListItem', () => { sortPriority: 0, duration: fakeNow.getTime() - fake2MinutesAgo.getTime(), isMuted: false, + tracked: true, }); }); @@ -316,6 +326,7 @@ describe('alertToListItem', () => { activeStartDate: fake2MinutesAgo.toISOString(), actionGroupId: 'default', flapping: false, + tracked: true, }; expect(alertToListItem(fakeNow.getTime(), 'id', alert)).toEqual({ @@ -326,6 +337,7 @@ describe('alertToListItem', () => { sortPriority: 0, duration: fakeNow.getTime() - fake2MinutesAgo.getTime(), isMuted: true, + tracked: true, }); }); @@ -335,6 +347,7 @@ describe('alertToListItem', () => { muted: false, actionGroupId: 'default', flapping: false, + tracked: true, }; expect(alertToListItem(fakeNow.getTime(), 'id', alert)).toEqual({ @@ -345,6 +358,7 @@ describe('alertToListItem', () => { duration: 0, sortPriority: 0, isMuted: false, + tracked: true, }); }); @@ -354,6 +368,7 @@ describe('alertToListItem', () => { muted: true, actionGroupId: 'default', flapping: false, + tracked: true, }; expect(alertToListItem(fakeNow.getTime(), 'id', alert)).toEqual({ alert: 'id', @@ -363,6 +378,7 @@ describe('alertToListItem', () => { duration: 0, sortPriority: 1, isMuted: true, + tracked: true, }); }); }); @@ -457,12 +473,14 @@ describe('tabbed content', () => { muted: false, actionGroupId: 'default', flapping: false, + tracked: true, }, second_rule: { status: 'Active', muted: false, actionGroupId: 'action group id unknown', flapping: false, + tracked: true, }, }, }); @@ -544,6 +562,7 @@ function mockRuleSummary(overloads: Partial = {}): RuleSummary { muted: false, actionGroupId: 'testActionGroup', flapping: false, + tracked: true, }, }, executionDuration: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx index 38b43114452ef0..7a5d12aad5e937 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx @@ -190,6 +190,7 @@ export function alertToListItem( const start = alert?.activeStartDate ? new Date(alert.activeStartDate) : undefined; const duration = start ? durationEpoch - start.valueOf() : 0; const sortPriority = getSortPriorityByStatus(alert?.status); + const tracked = !!alert?.tracked; return { alert: alertId, status, @@ -198,6 +199,7 @@ export function alertToListItem( isMuted, sortPriority, flapping: alert.flapping, + tracked, ...(alert.maintenanceWindowIds ? { maintenanceWindowIds: alert.maintenanceWindowIds } : {}), }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx index 616f17a2ee685c..05dedf30674183 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_alert_list.tsx @@ -10,7 +10,12 @@ import moment, { Duration } from 'moment'; import { padStart, chunk } from 'lodash'; import { EuiBasicTable, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { AlertStatus, ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; +import { + AlertStatus, + ALERT_STATUS_ACTIVE, + ALERT_STATUS_RECOVERED, + ALERT_STATUS_UNTRACKED, +} from '@kbn/rule-data-utils'; import { AlertStatusValues, MaintenanceWindow } from '@kbn/alerting-plugin/common'; import { DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; import { Pagination } from '../../../../types'; @@ -20,7 +25,13 @@ import { AlertLifecycleStatusBadge } from '../../../components/alert_lifecycle_s import { useBulkGetMaintenanceWindows } from '../../alerts_table/hooks/use_bulk_get_maintenance_windows'; import { MaintenanceWindowBaseCell } from '../../alerts_table/maintenance_windows/cell'; -export const getConvertedAlertStatus = (status: AlertStatusValues): AlertStatus => { +export const getConvertedAlertStatus = ( + status: AlertStatusValues, + alert: AlertListItem +): AlertStatus => { + if (!alert.tracked) { + return ALERT_STATUS_UNTRACKED; + } if (status === 'Active') { return ALERT_STATUS_ACTIVE; } @@ -151,7 +162,7 @@ export const RuleAlertList = (props: RuleAlertListProps) => { ), width: '15%', render: (value: AlertStatusValues, alert: AlertListItem) => { - const convertedStatus = getConvertedAlertStatus(value); + const convertedStatus = getConvertedAlertStatus(value, alert); return ( ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx index 1826894ef70f9c..7e660a30f7ec9c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx @@ -170,6 +170,7 @@ function mockRuleSummary(overloads: Partial = {}): any { status: 'OK', muted: false, flapping: false, + tracked: true, }, }, executionDuration: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts index d72e381c170ab6..01ea94fdea8df5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts @@ -104,6 +104,7 @@ export function mockRuleSummary(overloads: Partial = {}): RuleSumma muted: false, actionGroupId: 'testActionGroup', flapping: false, + tracked: true, }, }, executionDuration: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/types.ts index 3de1f6f464c88a..6b5239702e567d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/types.ts @@ -15,6 +15,7 @@ export interface AlertListItem { sortPriority: number; flapping: boolean; maintenanceWindowIds?: string[]; + tracked: boolean; } export interface RefreshToken { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts index c4620416f4bd66..39eaa216e7e04a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts @@ -95,7 +95,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex }); }); - it('should create recovered-instance events for all alerts', async () => { + it('should create untracked-instance events for all alerts', async () => { const { body: createdRule } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') @@ -138,7 +138,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex provider: 'alerting', actions: new Map([ // make sure the counts of the # of events per type are as expected - ['recovered-instance', { equal: 2 }], + ['untracked-instance', { equal: 2 }], ]), }); }); @@ -151,7 +151,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex savedObjects: [ { type: 'alert', id: ruleId, rel: 'primary', type_id: 'test.cumulative-firing' }, ], - message: "instance 'instance-0' has recovered due to the rule was disabled", + message: "instance 'instance-0' has been untracked because the rule was disabled", shouldHaveEventEnd: false, shouldHaveTask: false, ruleTypeId: createdRule.rule_type_id, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts index 2aff79b8997b80..2662ba69f3025e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts @@ -24,6 +24,7 @@ const InstanceActions = new Set([ 'new-instance', 'active-instance', 'recovered-instance', + 'untracked-instance', ]); // eslint-disable-next-line import/no-default-export diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get_alert_summary.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get_alert_summary.ts index 6a825be98d3271..87546a8649ce3d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get_alert_summary.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/get_alert_summary.ts @@ -183,6 +183,7 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo status: 'OK', muted: true, flapping: false, + tracked: true, }, }); }); @@ -248,11 +249,13 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertA.activeStartDate, flapping: false, + tracked: true, }, alertB: { status: 'OK', muted: false, flapping: false, + tracked: true, }, alertC: { status: 'Active', @@ -260,11 +263,13 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertC.activeStartDate, flapping: false, + tracked: true, }, alertD: { status: 'OK', muted: true, flapping: false, + tracked: true, }, }; expect(actualAlerts).to.eql(expectedAlerts); @@ -332,12 +337,14 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertA.activeStartDate, flapping: false, + tracked: true, maintenanceWindowIds: [createdMaintenanceWindow.id], }, alertB: { status: 'OK', muted: false, flapping: false, + tracked: true, maintenanceWindowIds: [createdMaintenanceWindow.id], }, alertC: { @@ -346,12 +353,14 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertC.activeStartDate, flapping: false, + tracked: true, maintenanceWindowIds: [createdMaintenanceWindow.id], }, alertD: { status: 'OK', muted: true, flapping: false, + tracked: true, }, }; expect(actualAlerts).to.eql(expectedAlerts); @@ -398,11 +407,13 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertA.activeStartDate, flapping: false, + tracked: true, }, alertB: { status: 'OK', muted: false, flapping: false, + tracked: true, }, alertC: { status: 'Active', @@ -410,11 +421,13 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo actionGroupId: 'default', activeStartDate: actualAlerts.alertC.activeStartDate, flapping: false, + tracked: true, }, alertD: { status: 'OK', muted: true, flapping: false, + tracked: true, }, }; expect(actualAlerts).to.eql(expectedAlerts); From bacebd27e081246412911ff487cc3d903167b791 Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Wed, 27 Sep 2023 16:44:52 -0600 Subject: [PATCH 17/22] [Security solution] AWS Bedrock connector (#166662) --- docs/management/action-types.asciidoc | 12 +- .../connectors/action-types/bedrock.asciidoc | 68 +++ .../connectors/images/bedrock-connector.png | Bin 0 -> 303619 bytes .../connectors/images/bedrock-params.png | Bin 0 -> 197882 bytes .../connectors/images/gen-ai-connector.png | Bin 227205 -> 265510 bytes docs/management/connectors/index.asciidoc | 1 + docs/settings/alert-action-settings.asciidoc | 2 +- package.json | 2 + .../impl/assistant/api.test.tsx | 62 +-- .../impl/assistant/api.tsx | 41 +- .../impl/assistant/assistant_title/index.tsx | 1 - .../conversation_settings.tsx | 6 - .../assistant/settings/assistant_settings.tsx | 10 +- .../impl/assistant_context/types.tsx | 1 + .../connector_selector/index.tsx | 137 ++++-- .../action_type_selector_modal.tsx | 62 +++ .../connector_selector_inline.test.tsx | 4 - .../connector_selector_inline.tsx | 182 ++----- .../connectorland/connector_setup/index.tsx | 104 ++-- .../impl/connectorland/helpers.tsx | 6 + .../use_load_connectors/index.tsx | 7 +- .../mock/test_providers/test_providers.tsx | 6 + .../server/__mocks__/action_result_data.ts | 30 +- .../execute_custom_llm_chain/index.test.ts | 8 +- .../execute_custom_llm_chain/index.ts | 5 +- .../server/lib/langchain/helpers.test.ts | 79 +-- .../server/lib/langchain/helpers.ts | 24 - .../langchain/llm/actions_client_llm.test.ts | 78 +-- .../lib/langchain/llm/actions_client_llm.ts | 44 +- .../server/lib/langchain/types.ts | 16 + .../post_actions_connector_execute.test.ts | 24 +- .../routes/post_actions_connector_execute.ts | 13 +- .../schemas/post_actions_connector_execute.ts | 20 +- .../common/bedrock/constants.ts | 25 + .../stack_connectors/common/bedrock/schema.ts | 45 ++ .../stack_connectors/common/bedrock/types.ts | 23 + .../common/gen_ai/constants.ts | 5 +- .../stack_connectors/common/gen_ai/schema.ts | 34 +- .../stack_connectors/common/gen_ai/types.ts | 32 +- .../connector_types/bedrock/bedrock.test.tsx | 83 ++++ .../connector_types/bedrock/bedrock.tsx | 61 +++ .../bedrock/connector.test.tsx | 161 +++++++ .../connector_types/bedrock/connector.tsx | 27 ++ .../connector_types/bedrock/constants.tsx | 117 +++++ .../public/connector_types/bedrock/index.ts | 8 + .../public/connector_types/bedrock/logo.tsx | 30 ++ .../connector_types/bedrock/params.test.tsx | 177 +++++++ .../public/connector_types/bedrock/params.tsx | 118 +++++ .../connector_types/bedrock/translations.ts | 99 ++++ .../public/connector_types/bedrock/types.ts | 27 ++ .../connector_types/gen_ai/gen_ai.test.tsx | 2 +- .../public/connector_types/gen_ai/gen_ai.tsx | 4 +- .../public/connector_types/gen_ai/types.ts | 4 +- .../public/connector_types/index.ts | 2 + .../connector_types/bedrock/bedrock.test.ts | 155 ++++++ .../server/connector_types/bedrock/bedrock.ts | 150 ++++++ .../connector_types/bedrock/index.test.ts | 82 ++++ .../server/connector_types/bedrock/index.ts | 53 +++ .../connector_types/bedrock/render.test.ts | 47 ++ .../server/connector_types/bedrock/render.ts | 26 + .../gen_ai/create_dashboard.test.ts | 12 +- .../gen_ai/create_dashboard.ts | 6 +- .../connector_types/gen_ai/dashboard.ts | 2 +- .../connector_types/gen_ai/gen_ai.test.ts | 100 ++-- .../server/connector_types/gen_ai/gen_ai.ts | 98 ++-- .../connector_types/gen_ai/index.test.ts | 16 +- .../server/connector_types/gen_ai/index.ts | 19 +- .../server/connector_types/index.ts | 2 + .../stack_connectors/server/plugin.test.ts | 11 +- .../alerting_api_integration/common/config.ts | 1 + .../server/bedrock_simulation.ts | 54 +++ .../tests/actions/connector_types/bedrock.ts | 450 ++++++++++++++++++ .../tests/actions/connector_types/gen_ai.ts | 2 +- .../group2/tests/actions/index.ts | 1 + .../check_registered_connector_types.ts | 1 + .../check_registered_task_types.ts | 1 + yarn.lock | 12 + 77 files changed, 2732 insertions(+), 708 deletions(-) create mode 100644 docs/management/connectors/action-types/bedrock.asciidoc create mode 100644 docs/management/connectors/images/bedrock-connector.png create mode 100644 docs/management/connectors/images/bedrock-params.png create mode 100644 x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/action_type_selector_modal.tsx create mode 100644 x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts create mode 100644 x-pack/plugins/stack_connectors/common/bedrock/constants.ts create mode 100644 x-pack/plugins/stack_connectors/common/bedrock/schema.ts create mode 100644 x-pack/plugins/stack_connectors/common/bedrock/types.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/constants.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/index.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/logo.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.test.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.tsx create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts create mode 100644 x-pack/plugins/stack_connectors/public/connector_types/bedrock/types.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts create mode 100644 x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts create mode 100644 x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts diff --git a/docs/management/action-types.asciidoc b/docs/management/action-types.asciidoc index 28aa218f3b6c8e..67dd4e3fd0019c 100644 --- a/docs/management/action-types.asciidoc +++ b/docs/management/action-types.asciidoc @@ -7,6 +7,10 @@ Connectors provide a central place to store connection information for services [cols="2"] |=== +a| <> + +| Send a request to AWS Bedrock. + a| <> | Send a request to D3 Security. @@ -15,10 +19,6 @@ a| <> | Send email from your server. -a| <> - -| Send a request to OpenAI. - a| <> | Create an incident in {ibm-r}. @@ -35,6 +35,10 @@ a| <> | Send a message to a Microsoft Teams channel. +a| <> + +| Send a request to OpenAI. + a| <> | Create or close an alert in {opsgenie}. diff --git a/docs/management/connectors/action-types/bedrock.asciidoc b/docs/management/connectors/action-types/bedrock.asciidoc new file mode 100644 index 00000000000000..afefc5914435f1 --- /dev/null +++ b/docs/management/connectors/action-types/bedrock.asciidoc @@ -0,0 +1,68 @@ +[[bedrock-action-type]] +== AWS Bedrock connector and action +++++ +AWS Bedrock +++++ +:frontmatter-description: Add a connector that can send requests to AWS Bedrock. +:frontmatter-tags-products: [kibana] +:frontmatter-tags-content-type: [how-to] +:frontmatter-tags-user-goals: [configure] + + +The AWS Bedrock connector uses https://github.com/axios/axios[axios] to send a POST request to AWS Bedrock. The connector uses the <> to send the request. + +[float] +[[define-bedrock-ui]] +=== Create connectors in {kib} + +You can create connectors in *{stack-manage-app} > {connectors-ui}*. For example: + +[role="screenshot"] +// TODO: need logo before screenshot +image::management/connectors/images/bedrock-connector.png[AWS Bedrock connector] + +[float] +[[bedrock-connector-configuration]] +==== Connector configuration + +AWS Bedrock connectors have the following configuration properties: + +Name:: The name of the connector. +API URL:: The AWS Bedrock request URL. +Default model:: The GAI model for AWS Bedrock to use. Current support is for the Anthropic Claude models, defaulting to Claude 2. The model can be set on a per request basis by including a "model" parameter alongside the request body. +Region:: The AWS Bedrock request URL. +Access Key:: The AWS access key for authentication. +Secret:: The secret for authentication. + +[float] +[[bedrock-action-configuration]] +=== Test connectors + +You can test connectors with the <> or +as you're creating or editing the connector in {kib}. For example: + +[role="screenshot"] +// TODO: need logo before screenshot +image::management/connectors/images/bedrock-params.png[AWS Bedrock params test] + +The AWS Bedrock actions have the following configuration properties. + +Body:: A stringified JSON payload sent to the AWS Bedrock Invoke Model API URL. For example: ++ +[source,text] +-- +{ + body: JSON.stringify({ + prompt: `${combinedMessages} \n\nAssistant:`, + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'] + }) +} +-- +Model:: An optional string that will overwrite the connector's default model. For + +[float] +[[bedrock-connector-networking-configuration]] +=== Connector networking configuration + +Use the <> to customize connector networking configurations, such as proxies, certificates, or TLS settings. You can set configurations that apply to all your connectors or use `xpack.actions.customHostSettings` to set per-host configurations. diff --git a/docs/management/connectors/images/bedrock-connector.png b/docs/management/connectors/images/bedrock-connector.png new file mode 100644 index 0000000000000000000000000000000000000000..22a537183171de4e7aa029369923f4d11529c716 GIT binary patch literal 303619 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%0Drf;@B+K5?PuH56 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 literal 227205 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�|;SGQQfI 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�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

X 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 IF>reDUugAw9smFU diff --git a/docs/management/connectors/index.asciidoc b/docs/management/connectors/index.asciidoc index a30bc26ca2511c..e7ef07ba4f7371 100644 --- a/docs/management/connectors/index.asciidoc +++ b/docs/management/connectors/index.asciidoc @@ -1,3 +1,4 @@ +include::action-types/bedrock.asciidoc[leveloffset=+1] include::action-types/d3security.asciidoc[leveloffset=+1] include::action-types/email.asciidoc[leveloffset=+1] include::action-types/gen-ai.asciidoc[leveloffset=+1] diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 8b05c3108df00b..fff867cc65a2ae 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -138,7 +138,7 @@ WARNING: This feature is available in {kib} 7.17.4 and 8.3.0 onwards but is not A boolean value indicating that a footer with a relevant link should be added to emails sent as alerting actions. Default: true. `xpack.actions.enabledActionTypes` {ess-icon}:: -A list of action types that are enabled. It defaults to `["*"]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.email`, `.index`, `.jira`, `.opsgenie`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, .`servicenow-itom`, `.servicenow-sir`, `.slack`, `.swimlane`, `.teams`, `.tines`, `.torq`, `.xmatters`, `.gen-ai`, `.d3security`, and `.webhook`. An empty list `[]` will disable all action types. +A list of action types that are enabled. It defaults to `["*"]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.email`, `.index`, `.jira`, `.opsgenie`, `.pagerduty`, `.resilient`, `.server-log`, `.servicenow`, .`servicenow-itom`, `.servicenow-sir`, `.slack`, `.swimlane`, `.teams`, `.tines`, `.torq`, `.xmatters`, `.gen-ai`, `.bedrock`, `.d3security`, and `.webhook`. An empty list `[]` will disable all action types. + Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. diff --git a/package.json b/package.json index 1394e14a8373ea..6f6f4352380e1b 100644 --- a/package.json +++ b/package.json @@ -842,6 +842,7 @@ "antlr4ts": "^0.5.0-alpha.3", "archiver": "^5.3.1", "async": "^3.2.3", + "aws4": "^1.12.0", "axios": "^1.4.0", "base64-js": "^1.3.1", "bitmap-sdf": "^1.0.3", @@ -1272,6 +1273,7 @@ "@types/adm-zip": "^0.5.0", "@types/archiver": "^5.3.1", "@types/async": "^3.2.3", + "@types/aws4": "^1.5.0", "@types/babel__core": "^7.20.0", "@types/babel__generator": "^7.6.4", "@types/babel__helper-plugin-utils": "^7.10.0", 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 2f46e99d12b070..0f5c06ba782fb4 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 @@ -46,7 +46,7 @@ describe('fetchConnectorExecuteAction', () => { expect(mockHttp.fetch).toHaveBeenCalledWith( '/internal/elastic_assistant/actions/connector/foo/_execute', { - body: '{"params":{"subActionParams":{"body":"{\\"model\\":\\"gpt-4\\",\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"This is a test\\"}],\\"n\\":1,\\"stop\\":null,\\"temperature\\":0.2}"},"subAction":"test"}}', + body: '{"params":{"subActionParams":{"model":"gpt-4","messages":[{"role":"user","content":"This is a test"}],"n":1,"stop":null,"temperature":0.2},"subAction":"invokeAI"}}', headers: { 'Content-Type': 'application/json' }, method: 'POST', signal: undefined, @@ -65,7 +65,7 @@ describe('fetchConnectorExecuteAction', () => { await fetchConnectorExecuteAction(testProps); expect(mockHttp.fetch).toHaveBeenCalledWith('/api/actions/connector/foo/_execute', { - body: '{"params":{"subActionParams":{"body":"{\\"model\\":\\"gpt-4\\",\\"messages\\":[{\\"role\\":\\"user\\",\\"content\\":\\"This is a test\\"}],\\"n\\":1,\\"stop\\":null,\\"temperature\\":0.2}"},"subAction":"test"}}', + body: '{"params":{"subActionParams":{"model":"gpt-4","messages":[{"role":"user","content":"This is a test"}],"n":1,"stop":null,"temperature":0.2},"subAction":"invokeAI"}}', headers: { 'Content-Type': 'application/json' }, method: 'POST', signal: undefined, @@ -88,7 +88,7 @@ describe('fetchConnectorExecuteAction', () => { }); it('returns API_ERROR when there are no choices', async () => { - (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'ok', data: {} }); + (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'ok', data: '' }); const testProps: FetchConnectorExecuteAction = { assistantLangChain: false, http: mockHttp, @@ -101,46 +101,12 @@ describe('fetchConnectorExecuteAction', () => { expect(result).toBe(API_ERROR); }); - it('return the trimmed first `choices` `message` `content` when the API call is successful', async () => { - (mockHttp.fetch as jest.Mock).mockResolvedValue({ - status: 'ok', - data: { - choices: [ - { - message: { - content: ' Test response ', // leading and trailing whitespace - }, - }, - ], - }, - }); - - const testProps: FetchConnectorExecuteAction = { - assistantLangChain: false, - http: mockHttp, - messages, - apiConfig, - }; - - const result = await fetchConnectorExecuteAction(testProps); - - 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, - }, - }, - ], - }, + data: content, }); const testProps: FetchConnectorExecuteAction = { @@ -160,15 +126,7 @@ describe('fetchConnectorExecuteAction', () => { (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'ok', - data: { - choices: [ - { - message: { - content, - }, - }, - ], - }, + data: content, }); const testProps: FetchConnectorExecuteAction = { @@ -188,15 +146,7 @@ describe('fetchConnectorExecuteAction', () => { (mockHttp.fetch as jest.Mock).mockResolvedValue({ status: 'ok', - data: { - choices: [ - { - message: { - content, - }, - }, - ], - }, + data: content, }); const testProps: FetchConnectorExecuteAction = { 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 6d3452b6f78803..b8b1455634a284 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/api.tsx @@ -44,15 +44,14 @@ export const fetchConnectorExecuteAction = async ({ temperature: 0.2, } : { + // Azure OpenAI and Bedrock invokeAI both expect this body format messages: outboundMessages, }; const requestBody = { params: { - subActionParams: { - body: JSON.stringify(body), - }, - subAction: 'test', + subActionParams: body, + subAction: 'invokeAI', }, }; @@ -61,29 +60,23 @@ export const fetchConnectorExecuteAction = async ({ ? `/internal/elastic_assistant/actions/connector/${apiConfig?.connectorId}/_execute` : `/api/actions/connector/${apiConfig?.connectorId}/_execute`; - // TODO: Find return type for this API - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const response = await http.fetch(path, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(requestBody), - signal, - }); - - const data = response.data; - if (response.status !== 'ok') { + const response = await http.fetch<{ connector_id: string; status: string; data: string }>( + path, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + signal, + } + ); + + if (response.status !== 'ok' || !response.data) { return API_ERROR; } - if (data.choices && data.choices.length > 0 && data.choices[0].message.content) { - const result = data.choices[0].message.content.trim(); - - return assistantLangChain ? getFormattedMessageContent(result) : result; - } else { - return API_ERROR; - } + return assistantLangChain ? getFormattedMessageContent(response.data) : response.data; } catch (error) { return API_ERROR; } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx index ccf04c38f5c933..b3dcd0ae084292 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_title/index.tsx @@ -110,7 +110,6 @@ export const AssistantTitle: React.FC<{ {}} selectedConnectorId={selectedConnectorId} selectedConversation={selectedConversation} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx index a0c8226b3ea7e4..e7f0ea06a72846 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_settings/conversation_settings.tsx @@ -8,7 +8,6 @@ import { EuiFormRow, EuiLink, EuiTitle, EuiText, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; -import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; import { HttpSetup } from '@kbn/core-http-browser'; import { FormattedMessage } from '@kbn/i18n-react'; import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/public/common'; @@ -27,7 +26,6 @@ import { useLoadConnectors } from '../../../connectorland/use_load_connectors'; import { getGenAiConfig } from '../../../connectorland/helpers'; export interface ConversationSettingsProps { - actionTypeRegistry: ActionTypeRegistryContract; allSystemPrompts: Prompt[]; conversationSettings: UseAssistantContext['conversations']; defaultConnectorId?: string; @@ -46,7 +44,6 @@ export interface ConversationSettingsProps { */ export const ConversationSettings: React.FC = React.memo( ({ - actionTypeRegistry, allSystemPrompts, defaultConnectorId, defaultProvider, @@ -250,10 +247,7 @@ export const ConversationSettings: React.FC = React.m } > {}} onConnectorSelectionChange={handleOnConnectorSelectionChange} selectedConnectorId={selectedConnector?.id} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx index 23712d8e74402e..e8e1994e85ef7c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/settings/assistant_settings.tsx @@ -76,13 +76,8 @@ export const AssistantSettings: React.FC = React.memo( selectedConversation: defaultSelectedConversation, setSelectedConversationId, }) => { - const { - actionTypeRegistry, - assistantLangChain, - http, - selectedSettingsTab, - setSelectedSettingsTab, - } = useAssistantContext(); + const { assistantLangChain, http, selectedSettingsTab, setSelectedSettingsTab } = + useAssistantContext(); const { conversationSettings, defaultAllow, @@ -267,7 +262,6 @@ export const AssistantSettings: React.FC = React.memo( conversationSettings={conversationSettings} setUpdatedConversationSettings={setUpdatedConversationSettings} allSystemPrompts={systemPromptSettings} - actionTypeRegistry={actionTypeRegistry} selectedConversation={selectedConversation} onSelectedConversationChange={onHandleSelectedConversationChange} http={http} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx index 94b78b459c9347..573581091eebf1 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx @@ -45,6 +45,7 @@ export interface ConversationTheme { export interface Conversation { apiConfig: { connectorId?: string; + connectorTypeTitle?: string; defaultSystemPromptId?: string; provider?: OpenAiProviderType; model?: string; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx index df3f0b54cd14fc..da9daff7c080ef 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector/index.tsx @@ -8,61 +8,66 @@ import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSuperSelect, EuiText } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; -import { - ActionConnector, - ActionTypeRegistryContract, -} from '@kbn/triggers-actions-ui-plugin/public'; +import { ActionConnector, ActionType } from '@kbn/triggers-actions-ui-plugin/public'; -import { HttpSetup } from '@kbn/core-http-browser'; import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; -import { GEN_AI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/public/common'; +import { ActionTypeSelectorModal } from '../connector_selector_inline/action_type_selector_modal'; import { useLoadConnectors } from '../use_load_connectors'; import * as i18n from '../translations'; import { useLoadActionTypes } from '../use_load_action_types'; import { useAssistantContext } from '../../assistant_context'; -import { getGenAiConfig } from '../helpers'; +import { getActionTypeTitle, getGenAiConfig } from '../helpers'; export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR'; + interface Props { - actionTypeRegistry: ActionTypeRegistryContract; - http: HttpSetup; isDisabled?: boolean; - onConnectorSelectionChange: (connector: ActionConnector | undefined) => void; + isOpen?: boolean; + onConnectorSelectionChange: (connector: AIConnector) => void; selectedConnectorId?: string; - onConnectorModalVisibilityChange?: (isVisible: boolean) => void; + displayFancy?: (displayText: string) => React.ReactNode; + setIsOpen?: (isOpen: boolean) => void; } +export type AIConnector = ActionConnector & { + connectorTypeTitle: string; +}; + export const ConnectorSelector: React.FC = React.memo( ({ - actionTypeRegistry, - http, isDisabled = false, - onConnectorModalVisibilityChange, + isOpen = false, + displayFancy, selectedConnectorId, onConnectorSelectionChange, + setIsOpen, }) => { - const { assistantAvailability } = useAssistantContext(); + const { actionTypeRegistry, http, assistantAvailability } = useAssistantContext(); // Connector Modal State const [isConnectorModalVisible, setIsConnectorModalVisible] = useState(false); const { data: actionTypes } = useLoadActionTypes({ http }); - const actionType = actionTypes?.find((at) => at.id === GEN_AI_CONNECTOR_ID) ?? { - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'platinum', - supportedFeatureIds: ['general'], - isSystemActionType: false, - id: '.gen-ai', - name: 'Generative AI', - enabled: true, - }; + + const [selectedActionType, setSelectedActionType] = useState(null); const { - data: connectors, - isLoading: isLoadingActionTypes, - isFetching: isFetchingActionTypes, + data: connectorsWithoutActionContext, + isLoading: isLoadingConnectors, + isFetching: isFetchingConnectors, refetch: refetchConnectors, } = useLoadConnectors({ http }); - const isLoading = isLoadingActionTypes || isFetchingActionTypes; + + const aiConnectors: AIConnector[] = useMemo( + () => + connectorsWithoutActionContext + ? connectorsWithoutActionContext.map((c) => ({ + ...c, + connectorTypeTitle: getActionTypeTitle(actionTypeRegistry.get(c.actionTypeId)), + })) + : [], + [actionTypeRegistry, connectorsWithoutActionContext] + ); + + const isLoading = isLoadingConnectors || isFetchingConnectors; const localIsDisabled = isDisabled || !assistantAvailability.hasConnectorsReadPrivilege; const addNewConnectorOption = useMemo(() => { @@ -72,7 +77,12 @@ export const ConnectorSelector: React.FC = React.memo( dropdownDisplay: ( - + {i18n.ADD_NEW_CONNECTOR} @@ -85,16 +95,17 @@ export const ConnectorSelector: React.FC = React.memo( }; }, []); - const connectorOptions = useMemo(() => { - return ( - connectors?.map((connector) => { - const apiProvider = getGenAiConfig(connector)?.apiProvider; + const connectorOptions = useMemo( + () => + aiConnectors.map((connector) => { + const connectorTypeTitle = + getGenAiConfig(connector)?.apiProvider ?? connector.connectorTypeTitle; const connectorDetails = connector.isPreconfigured ? i18n.PRECONFIGURED_CONNECTOR - : apiProvider; + : connectorTypeTitle; return { value: connector.id, - inputDisplay: connector.name, + inputDisplay: displayFancy ? displayFancy(connector.name) : connector.name, dropdownDisplay: ( {connector.name} @@ -106,9 +117,9 @@ export const ConnectorSelector: React.FC = React.memo( ), }; - }) ?? [] - ); - }, [connectors]); + }), + [aiConnectors, displayFancy] + ); // Only include add new connector option if user has privilege const allConnectorOptions = useMemo( @@ -120,22 +131,39 @@ export const ConnectorSelector: React.FC = React.memo( ); const cleanupAndCloseModal = useCallback(() => { - onConnectorModalVisibilityChange?.(false); + setIsOpen?.(false); setIsConnectorModalVisible(false); - }, [onConnectorModalVisibilityChange]); + setSelectedActionType(null); + }, [setIsOpen]); + + const [modalForceOpen, setModalForceOpen] = useState(isOpen); const onChange = useCallback( (connectorId: string) => { if (connectorId === ADD_NEW_CONNECTOR) { - onConnectorModalVisibilityChange?.(true); + setModalForceOpen(false); setIsConnectorModalVisible(true); return; } - const connector = connectors?.find((c) => c.id === connectorId); - onConnectorSelectionChange(connector); + const connector = aiConnectors.find((c) => c.id === connectorId); + if (connector) { + onConnectorSelectionChange(connector); + } + }, + [aiConnectors, onConnectorSelectionChange] + ); + + const onSaveConnector = useCallback( + (connector: ActionConnector) => { + onConnectorSelectionChange({ + ...connector, + connectorTypeTitle: getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId)), + }); + refetchConnectors?.(); + cleanupAndCloseModal(); }, - [connectors, onConnectorSelectionChange, onConnectorModalVisibilityChange] + [actionTypeRegistry, cleanupAndCloseModal, onConnectorSelectionChange, refetchConnectors] ); return ( @@ -146,19 +174,24 @@ export const ConnectorSelector: React.FC = React.memo( disabled={localIsDisabled} hasDividers={true} isLoading={isLoading} + isOpen={modalForceOpen} onChange={onChange} options={allConnectorOptions} valueOfSelected={selectedConnectorId ?? ''} /> - {isConnectorModalVisible && ( + {isConnectorModalVisible && !selectedActionType && ( + setIsConnectorModalVisible(false)} + onSelect={(actionType: ActionType) => setSelectedActionType(actionType)} + /> + )} + {isConnectorModalVisible && selectedActionType && ( { - onConnectorSelectionChange(connector); - refetchConnectors?.(); - cleanupAndCloseModal(); - }} + postSaveEventHandler={onSaveConnector} actionTypeRegistry={actionTypeRegistry} /> )} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/action_type_selector_modal.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/action_type_selector_modal.tsx new file mode 100644 index 00000000000000..c08de0facb3f10 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/action_type_selector_modal.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiKeyPadMenuItem, + EuiModal, + EuiModalBody, + EuiModalHeader, + EuiModalHeaderTitle, +} from '@elastic/eui'; +import { ActionType } from '@kbn/actions-plugin/common'; +import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; +import * as i18n from '../translations'; + +interface Props { + actionTypes?: ActionType[]; + actionTypeRegistry: ActionTypeRegistryContract; + onClose: () => void; + onSelect: (actionType: ActionType) => void; +} + +export const ActionTypeSelectorModal = ({ + actionTypes, + actionTypeRegistry, + onClose, + onSelect, +}: Props) => + actionTypes && actionTypes.length > 0 ? ( + + + {i18n.INLINE_CONNECTOR_PLACEHOLDER} + + + + + {actionTypes.map((actionType: ActionType) => { + const fullAction = actionTypeRegistry.get(actionType.id); + return ( + + onSelect(actionType)} + > + + + + ); + })} + + + + ) : null; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx index 3b1ff0be861812..b6e56d63523733 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.test.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { noop } from 'lodash/fp'; import { TestProviders } from '../../mock/test_providers/test_providers'; import { ConnectorSelectorInline } from './connector_selector_inline'; import * as i18n from '../translations'; @@ -64,7 +63,6 @@ describe('ConnectorSelectorInline', () => { @@ -83,7 +81,6 @@ describe('ConnectorSelectorInline', () => { @@ -102,7 +99,6 @@ describe('ConnectorSelectorInline', () => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx index d7f4a50f90ae95..c6539520861cc6 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_selector_inline/connector_selector_inline.tsx @@ -5,31 +5,24 @@ * 2.0. */ -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; -import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; - -import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; -import { - GEN_AI_CONNECTOR_ID, - OpenAiProviderType, -} from '@kbn/stack-connectors-plugin/public/common'; import { css } from '@emotion/css/dist/emotion-css.cjs'; +import { AIConnector, ConnectorSelector } from '../connector_selector'; import { Conversation } from '../../..'; import { useLoadConnectors } from '../use_load_connectors'; import * as i18n from '../translations'; -import { useLoadActionTypes } from '../use_load_action_types'; import { useAssistantContext } from '../../assistant_context'; import { useConversation } from '../../assistant/use_conversation'; -import { getGenAiConfig } from '../helpers'; +import { getActionTypeTitle, getGenAiConfig } from '../helpers'; export const ADD_NEW_CONNECTOR = 'ADD_NEW_CONNECTOR'; + interface Props { isDisabled?: boolean; selectedConnectorId?: string; selectedConversation?: Conversation; - onConnectorModalVisibilityChange?: (isVisible: boolean) => void; } const inputContainerClassName = css` @@ -69,131 +62,55 @@ const placeholderButtonClassName = css` `; /** - * A minimal and connected version of the ConnectorSelector component used in the Settings modal. + * A compact wrapper of the ConnectorSelector component used in the Settings modal. */ export const ConnectorSelectorInline: React.FC = React.memo( - ({ - isDisabled = false, - onConnectorModalVisibilityChange, - selectedConnectorId, - selectedConversation, - }) => { + ({ isDisabled = false, selectedConnectorId, selectedConversation }) => { const [isOpen, setIsOpen] = useState(false); const { actionTypeRegistry, assistantAvailability, http } = useAssistantContext(); const { setApiConfig } = useConversation(); - // Connector Modal State - const [isConnectorModalVisible, setIsConnectorModalVisible] = useState(false); - const { data: actionTypes } = useLoadActionTypes({ http }); - const actionType = actionTypes?.find((at) => at.id === GEN_AI_CONNECTOR_ID) ?? { - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'platinum', - supportedFeatureIds: ['general'], - isSystemActionType: false, - id: '.gen-ai', - name: 'Generative AI', - enabled: true, - }; - - const { - data: connectors, - isLoading: isLoadingActionTypes, - isFetching: isFetchingActionTypes, - refetch: refetchConnectors, - } = useLoadConnectors({ http }); - const isLoading = isLoadingActionTypes || isFetchingActionTypes; - const selectedConnectorName = - connectors?.find((c) => c.id === selectedConnectorId)?.name ?? - i18n.INLINE_CONNECTOR_PLACEHOLDER; - const localIsDisabled = isDisabled || !assistantAvailability.hasConnectorsReadPrivilege; - - const addNewConnectorOption = useMemo(() => { - return { - value: ADD_NEW_CONNECTOR, - inputDisplay: i18n.ADD_NEW_CONNECTOR, - dropdownDisplay: ( - - - - {i18n.ADD_NEW_CONNECTOR} - - - - {/* Right offset to compensate for 'selected' icon of EuiSuperSelect since native footers aren't supported*/} -

- - - ), - }; - }, []); - const connectorOptions = useMemo(() => { - return ( - connectors?.map((connector) => { - const apiProvider = getGenAiConfig(connector)?.apiProvider; - const connectorDetails = connector.isPreconfigured - ? i18n.PRECONFIGURED_CONNECTOR - : apiProvider; - return { - value: connector.id, - inputDisplay: ( - - {connector.name} - - ), - dropdownDisplay: ( - - {connector.name} - {connectorDetails && ( - -

{connectorDetails}

-
- )} -
- ), - }; - }) ?? [] - ); - }, [connectors]); + const { data: connectorsWithoutActionContext } = useLoadConnectors({ http }); - // Only include add new connector option if user has privilege - const allConnectorOptions = useMemo( + const aiConnectors: AIConnector[] = useMemo( () => - assistantAvailability.hasConnectorsAllPrivilege - ? [...connectorOptions, addNewConnectorOption] - : [...connectorOptions], - [addNewConnectorOption, assistantAvailability.hasConnectorsAllPrivilege, connectorOptions] + connectorsWithoutActionContext + ? connectorsWithoutActionContext.map((c) => ({ + ...c, + connectorTypeTitle: getActionTypeTitle(actionTypeRegistry.get(c.actionTypeId)), + })) + : [], + [actionTypeRegistry, connectorsWithoutActionContext] ); - const cleanupAndCloseModal = useCallback(() => { - onConnectorModalVisibilityChange?.(false); - setIsConnectorModalVisible(false); - }, [onConnectorModalVisibilityChange]); + const selectedConnectorName = + aiConnectors.find((c) => c.id === selectedConnectorId)?.name ?? + i18n.INLINE_CONNECTOR_PLACEHOLDER; + const localIsDisabled = isDisabled || !assistantAvailability.hasConnectorsReadPrivilege; const onConnectorClick = useCallback(() => { setIsOpen(!isOpen); }, [isOpen]); - const handleOnBlur = useCallback(() => setIsOpen(false), []); - const onChange = useCallback( - (connectorId: string, apiProvider?: OpenAiProviderType, model?: string) => { - setIsOpen(false); - + (connector: AIConnector) => { + const connectorId = connector.id; if (connectorId === ADD_NEW_CONNECTOR) { - onConnectorModalVisibilityChange?.(true); - setIsConnectorModalVisible(true); return; } - const connector = connectors?.find((c) => c.id === connectorId); const config = getGenAiConfig(connector); + const apiProvider = config?.apiProvider; + const model = config?.defaultModel; + setIsOpen(false); + if (selectedConversation != null) { setApiConfig({ conversationId: selectedConversation.id, apiConfig: { ...selectedConversation.apiConfig, connectorId, + connectorTypeTitle: connector.connectorTypeTitle, // With the inline component, prefer config args to handle 'new connector' case provider: apiProvider ?? config?.apiProvider, model: model ?? config?.defaultModel, @@ -201,16 +118,7 @@ export const ConnectorSelectorInline: React.FC = React.memo( }); } }, - [connectors, selectedConversation, onConnectorModalVisibilityChange, setApiConfig] - ); - - const placeholderComponent = useMemo( - () => ( - - {i18n.INLINE_CONNECTOR_PLACEHOLDER} - - ), - [] + [selectedConversation, setApiConfig] ); return ( @@ -229,18 +137,17 @@ export const ConnectorSelectorInline: React.FC = React.memo( {isOpen ? ( - ( + + {displayText} + + )} + isOpen + isDisabled={localIsDisabled} + selectedConnectorId={selectedConnectorId} + setIsOpen={setIsOpen} + onConnectorSelectionChange={onChange} /> ) : ( @@ -258,19 +165,6 @@ export const ConnectorSelectorInline: React.FC = React.memo( )} - {isConnectorModalVisible && ( - { - const config = getGenAiConfig(connector); - onChange(connector.id, config?.apiProvider, config?.defaultModel); - refetchConnectors?.(); - cleanupAndCloseModal(); - }} - actionTypeRegistry={actionTypeRegistry} - /> - )} ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx index 9429ad9435ea7b..32463004b12171 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/connector_setup/index.tsx @@ -10,11 +10,13 @@ import type { EuiCommentProps } from '@elastic/eui'; import { EuiAvatar, EuiBadge, EuiMarkdownFormat, EuiText, EuiTextAlign } from '@elastic/eui'; // eslint-disable-next-line @kbn/eslint/module_migration import styled from 'styled-components'; -import { ConnectorAddModal } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; -import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; +import { + ActionConnector, + ConnectorAddModal, +} from '@kbn/triggers-actions-ui-plugin/public/common/constants'; import { ActionType } from '@kbn/triggers-actions-ui-plugin/public'; -import { GEN_AI_CONNECTOR_ID } from '@kbn/stack-connectors-plugin/public/common'; +import { ActionTypeSelectorModal } from '../connector_selector_inline/action_type_selector_modal'; import { WELCOME_CONVERSATION } from '../../assistant/use_conversation/sample_conversations'; import { Conversation, Message } from '../../..'; import { useLoadActionTypes } from '../use_load_action_types'; @@ -26,7 +28,7 @@ import * as i18n from '../translations'; import { useAssistantContext } from '../../assistant_context'; import { useLoadConnectors } from '../use_load_connectors'; import { AssistantAvatar } from '../../assistant/assistant_avatar/assistant_avatar'; -import { getGenAiConfig } from '../helpers'; +import { getActionTypeTitle, getGenAiConfig } from '../helpers'; const ConnectorButtonWrapper = styled.div` margin-bottom: 10px; @@ -65,20 +67,8 @@ export const useConnectorSetup = ({ return conversationHasNoPresentationData(conversation); }); const { data: actionTypes } = useLoadActionTypes({ http }); - const actionType: ActionType = useMemo( - () => - actionTypes?.find((at) => at.id === GEN_AI_CONNECTOR_ID) ?? { - enabledInConfig: true, - enabledInLicense: true, - isSystemActionType: false, - minimumLicenseRequired: 'platinum', - supportedFeatureIds: ['general'], - id: '.gen-ai', - name: 'Generative AI', - enabled: true, - }, - [actionTypes] - ); + + const [selectedActionType, setSelectedActionType] = useState(null); // User constants const userName = useMemo( @@ -190,6 +180,45 @@ export const useConnectorSetup = ({ [assistantName, commentBody, conversation.messages, currentMessageIndex, userName] ); + const onSaveConnector = useCallback( + (connector: ActionConnector) => { + const config = getGenAiConfig(connector); + // add action type title to new connector + const connectorTypeTitle = getActionTypeTitle(actionTypeRegistry.get(connector.actionTypeId)); + Object.values(conversations).forEach((c) => { + setApiConfig({ + conversationId: c.id, + apiConfig: { + ...c.apiConfig, + connectorId: connector.id, + connectorTypeTitle, + provider: config?.apiProvider, + model: config?.defaultModel, + }, + }); + }); + + refetchConnectors?.(); + setIsConnectorModalVisible(false); + appendMessage({ + conversationId: conversation.id, + message: { + role: 'assistant', + content: 'Connector setup complete!', + timestamp: new Date().toLocaleString(), + }, + }); + }, + [ + actionTypeRegistry, + appendMessage, + conversation.id, + conversations, + refetchConnectors, + setApiConfig, + ] + ); + return { comments, prompt: ( @@ -212,36 +241,19 @@ export const useConnectorSetup = ({ )} - {isConnectorModalVisible && ( + {isConnectorModalVisible && !selectedActionType && ( + setIsConnectorModalVisible(false)} + onSelect={(actionType: ActionType) => setSelectedActionType(actionType)} + /> + )} + {isConnectorModalVisible && selectedActionType && ( setIsConnectorModalVisible(false)} - postSaveEventHandler={(connector: ActionConnector) => { - const config = getGenAiConfig(connector); - // Add connector to all conversations - Object.values(conversations).forEach((c) => { - setApiConfig({ - conversationId: c.id, - apiConfig: { - ...c.apiConfig, - connectorId: connector.id, - provider: config?.apiProvider, - model: config?.defaultModel, - }, - }); - }); - - refetchConnectors?.(); - setIsConnectorModalVisible(false); - appendMessage({ - conversationId: conversation.id, - message: { - role: 'assistant', - content: 'Connector setup complete!', - timestamp: new Date().toLocaleString(), - }, - }); - }} + postSaveEventHandler={onSaveConnector} actionTypeRegistry={actionTypeRegistry} /> )} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx index ffd9604ab328fb..b5db94fe041d33 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/helpers.tsx @@ -8,6 +8,7 @@ import type { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; import { ActionConnectorProps } from '@kbn/triggers-actions-ui-plugin/public/types'; import { OpenAiProviderType } from '@kbn/stack-connectors-plugin/common/gen_ai/constants'; +import { ActionTypeModel } from '@kbn/triggers-actions-ui-plugin/public'; interface GenAiConfig { apiProvider?: OpenAiProviderType; @@ -29,3 +30,8 @@ export const getGenAiConfig = (connector: ActionConnector | undefined): GenAiCon } return undefined; }; + +export const getActionTypeTitle = (actionType: ActionTypeModel): string => { + // This is for types, it is always defined for the AI connectors + return actionType.actionTypeTitle ?? actionType.id; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx index 9f67285ac3dc91..b0947cf24481c0 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/use_load_connectors/index.tsx @@ -34,11 +34,10 @@ export const useLoadConnectors = ({ QUERY_KEY, async () => { const queryResult = await loadConnectors({ http }); - const filteredData = queryResult.filter( - (connector) => !connector.isMissingSecrets && connector.actionTypeId === '.gen-ai' + return queryResult.filter( + (connector) => + !connector.isMissingSecrets && ['.bedrock', '.gen-ai'].includes(connector.actionTypeId) ); - - return filteredData; }, { retry: false, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx index 057db39f66ba25..c01e65dd4ed8c3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx @@ -44,6 +44,12 @@ export const TestProvidersComponent: React.FC = ({ providerContext, }) => { const actionTypeRegistry = actionTypeRegistryMock.create(); + actionTypeRegistry.get = jest.fn().mockReturnValue({ + id: '12345', + actionTypeId: '.gen-ai', + actionTypeTitle: 'OpenAI', + iconClass: 'logoGenAI', + }); const mockGetComments = jest.fn(() => []); const mockHttp = httpServiceMock.createStartContract({ basePath: '/test' }); const queryClient = new QueryClient({ diff --git a/x-pack/plugins/elastic_assistant/server/__mocks__/action_result_data.ts b/x-pack/plugins/elastic_assistant/server/__mocks__/action_result_data.ts index 280a86d2ac326e..17aa4b83ca67b9 100644 --- a/x-pack/plugins/elastic_assistant/server/__mocks__/action_result_data.ts +++ b/x-pack/plugins/elastic_assistant/server/__mocks__/action_result_data.ts @@ -5,32 +5,4 @@ * 2.0. */ -/** - * A mock `data` property from an `actionResult` response, which is returned - * from the `execute` method of the Actions plugin. - * - * Given the following example: - * - * ```ts - * const actionResult = await actionsClient.execute(requestBody); - * ``` - * - * In the above example, `actionResult.data` would be this mock data. - */ -export const mockActionResultData = { - id: 'chatcmpl-7sFVvksgFtMUac3pY5bTypFAKaGX1', - object: 'chat.completion', - created: 1693163703, - model: 'gpt-4', - choices: [ - { - index: 0, - finish_reason: 'stop', - message: { - role: 'assistant', - content: 'Yes, your name is Andrew. How can I assist you further, Andrew?', - }, - }, - ], - usage: { completion_tokens: 16, prompt_tokens: 140, total_tokens: 156 }, -}; +export const mockActionResponse = 'Yes, your name is Andrew. How can I assist you further, Andrew?'; 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 67fb3859b99438..d9e301d5571901 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 @@ -8,9 +8,9 @@ import { KibanaRequest } from '@kbn/core/server'; import { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; -import { ResponseBody } from '../helpers'; +import { ResponseBody } from '../types'; import { ActionsClientLlm } from '../llm/actions_client_llm'; -import { mockActionResultData } from '../../../__mocks__/action_result_data'; +import { mockActionResponse } from '../../../__mocks__/action_result_data'; import { langChainMessages } from '../../../__mocks__/lang_chain_messages'; import { callAgentExecutor } from '.'; import { loggerMock } from '@kbn/logging-mocks'; @@ -55,7 +55,7 @@ describe('callAgentExecutor', () => { ActionsClientLlm.prototype.getActionResultData = jest .fn() - .mockReturnValueOnce(mockActionResultData); + .mockReturnValueOnce(mockActionResponse); }); it('creates an instance of ActionsClientLlm with the expected context from the request', async () => { @@ -120,7 +120,7 @@ describe('callAgentExecutor', () => { expect(result).toEqual({ connector_id: 'mock-connector-id', - data: mockActionResultData, + data: mockActionResponse, status: 'ok', }); }); 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 b6a768ad695980..e6df7ce72a24cb 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 @@ -14,7 +14,7 @@ import { BaseMessage } from 'langchain/schema'; import { ChainTool, Tool } from 'langchain/tools'; import { ElasticsearchStore } from '../elasticsearch_store/elasticsearch_store'; -import { ResponseBody } from '../helpers'; +import { RequestBody, ResponseBody } from '../types'; import { ActionsClientLlm } from '../llm/actions_client_llm'; import { KNOWLEDGE_BASE_INDEX_PATTERN } from '../../../routes/knowledge_base/constants'; @@ -31,8 +31,7 @@ export const callAgentExecutor = async ({ esClient: ElasticsearchClient; langChainMessages: BaseMessage[]; logger: Logger; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - request: KibanaRequest; + request: KibanaRequest; }): Promise => { const llm = new ActionsClientLlm({ actions, connectorId, request, logger }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts index 1c62fab9df6cc4..1156a8e758c134 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.test.ts @@ -8,12 +8,7 @@ import type { Message } from '@kbn/elastic-assistant'; import { AIMessage, BaseMessage, HumanMessage, SystemMessage } from 'langchain/schema'; -import { - getLangChainMessage, - getLangChainMessages, - getMessageContentAndRole, - unsafeGetAssistantMessagesFromRequest, -} from './helpers'; +import { getLangChainMessage, getLangChainMessages, getMessageContentAndRole } from './helpers'; import { langChainMessages } from '../../__mocks__/lang_chain_messages'; describe('helpers', () => { @@ -110,76 +105,4 @@ describe('helpers', () => { }); }); }); - - describe('unsafeGetAssistantMessagesFromRequest', () => { - const rawSubActionParamsBody = { - messages: [ - { role: 'user', content: '\n\n\n\nWhat is my name?' }, - { - role: 'assistant', - content: - "Hello! Since we are communicating through text, I do not have the information about your name. Please feel free to share your name with me, if you'd like.", - }, - { role: 'user', content: '\n\nMy name is Andrew' }, - { - role: 'assistant', - content: - "Hi, Andrew! It's nice to meet you. How can I help you or what would you like to talk about today?", - }, - { role: 'user', content: '\n\nDo you know my name?' }, - ], - }; - - it('returns the expected assistant messages from a conversation', () => { - const result = unsafeGetAssistantMessagesFromRequest(JSON.stringify(rawSubActionParamsBody)); - - const expected = [ - { role: 'user', content: '\n\n\n\nWhat is my name?' }, - { - role: 'assistant', - content: - "Hello! Since we are communicating through text, I do not have the information about your name. Please feel free to share your name with me, if you'd like.", - }, - { role: 'user', content: '\n\nMy name is Andrew' }, - { - role: 'assistant', - content: - "Hi, Andrew! It's nice to meet you. How can I help you or what would you like to talk about today?", - }, - { role: 'user', content: '\n\nDo you know my name?' }, - ]; - - expect(result).toEqual(expected); - }); - - it('returns an empty array when the rawSubActionParamsBody is undefined', () => { - const result = unsafeGetAssistantMessagesFromRequest(undefined); - - expect(result).toEqual([]); - }); - - it('returns an empty array when the rawSubActionParamsBody messages[] array is empty', () => { - const hasEmptyMessages = { - messages: [], - }; - - const result = unsafeGetAssistantMessagesFromRequest(JSON.stringify(hasEmptyMessages)); - - expect(result).toEqual([]); - }); - - it('returns an empty array when the rawSubActionParamsBody shape is unexpected', () => { - const unexpected = { invalidKey: 'some_value' }; - - const result = unsafeGetAssistantMessagesFromRequest(JSON.stringify(unexpected)); - - expect(result).toEqual([]); - }); - - it('returns an empty array when the rawSubActionParamsBody is invalid JSON', () => { - const result = unsafeGetAssistantMessagesFromRequest('[]'); - - expect(result).toEqual([]); - }); - }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts index 90364dcfe75db5..c13977ddb1e7d0 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/helpers.ts @@ -31,27 +31,3 @@ export const getMessageContentAndRole = (prompt: string): Pick; - connector_id: string; -} - -/** An unsafe, temporary stub that parses assistant messages from the request with no validation */ -export const unsafeGetAssistantMessagesFromRequest = ( - rawSubActionParamsBody: string | undefined -): Array> => { - try { - if (rawSubActionParamsBody == null) { - return []; - } - - const subActionParamsBody = JSON.parse(rawSubActionParamsBody); // TODO: unsafe, no validation - const messages = subActionParamsBody?.messages; - - return Array.isArray(messages) ? messages : []; - } catch { - return []; - } -}; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.test.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.test.ts index b774d687c7ce18..8769e21770678c 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.test.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.test.ts @@ -10,12 +10,13 @@ import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plu import { loggerMock } from '@kbn/logging-mocks'; import { ActionsClientLlm } from './actions_client_llm'; -import { mockActionResultData } from '../../../__mocks__/action_result_data'; +import { mockActionResponse } from '../../../__mocks__/action_result_data'; +import { RequestBody } from '../types'; const connectorId = 'mock-connector-id'; const mockExecute = jest.fn().mockImplementation(() => ({ - data: mockActionResultData, + data: mockActionResponse, status: 'ok', })); @@ -27,19 +28,31 @@ const mockActions = { })), } as unknown as ActionsPluginStart; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mockRequest: KibanaRequest = { +const mockRequest: KibanaRequest = { params: { connectorId }, body: { params: { subActionParams: { - body: '{"messages":[{"role":"user","content":"\\n\\n\\n\\nWhat is my name?"},{"role":"assistant","content":"I\'m sorry, but I don\'t have the information about your name. You can tell me your name if you\'d like, and we can continue our conversation from there."},{"role":"user","content":"\\n\\nMy name is Andrew"},{"role":"assistant","content":"Hello, Andrew! It\'s nice to meet you. What would you like to talk about today?"},{"role":"user","content":"\\n\\nDo you know my name?"}]}', + messages: [ + { role: 'user', content: '\\n\\n\\n\\nWhat is my name?' }, + { + role: 'assistant', + content: + "I'm sorry, but I don't have the information about your name. You can tell me your name if you'd like, and we can continue our conversation from there.", + }, + { role: 'user', content: '\\n\\nMy name is Andrew' }, + { + role: 'assistant', + content: + "Hello, Andrew! It's nice to meet you. What would you like to talk about today?", + }, + { role: 'user', content: '\\n\\nDo you know my name?' }, + ], }, - subAction: 'test', + subAction: 'invokeAI', }, }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any -} as KibanaRequest; +} as KibanaRequest; const prompt = 'Do you know my name?'; @@ -59,7 +72,7 @@ describe('ActionsClientLlm', () => { await actionsClientLlm._call(prompt); // ignore the result - expect(actionsClientLlm.getActionResultData()).toEqual(mockActionResultData); + expect(actionsClientLlm.getActionResultData()).toEqual(mockActionResponse); }); }); @@ -116,50 +129,7 @@ describe('ActionsClientLlm', () => { }); it('rejects with the expected error the message has invalid content', async () => { - const invalidContent = { - id: 'chatcmpl-7sFVvksgFtMUac3pY5bTypFAKaGX1', - object: 'chat.completion', - created: 1693163703, - model: 'gpt-4', - choices: [ - { - index: 0, - finish_reason: 'stop', - message: { - role: 'assistant', - content: 1234, // <-- invalid content - }, - }, - ], - usage: { completion_tokens: 16, prompt_tokens: 140, total_tokens: 156 }, - }; - - mockExecute.mockImplementation(() => ({ - data: invalidContent, - status: 'ok', - })); - - const actionsClientLlm = new ActionsClientLlm({ - actions: mockActions, - connectorId, - logger: mockLogger, - request: mockRequest, - }); - - expect(actionsClientLlm._call(prompt)).rejects.toThrowError( - 'ActionsClientLlm: choices[0] message content should be a string, but it had an unexpected type: number' - ); - }); - - it('rejects with the expected error when choices is empty', async () => { - const invalidContent = { - id: 'chatcmpl-7sFVvksgFtMUac3pY5bTypFAKaGX1', - object: 'chat.completion', - created: 1693163703, - model: 'gpt-4', - choices: [], // <-- empty choices - usage: { completion_tokens: 16, prompt_tokens: 140, total_tokens: 156 }, - }; + const invalidContent = 1234; mockExecute.mockImplementation(() => ({ data: invalidContent, @@ -174,7 +144,7 @@ describe('ActionsClientLlm', () => { }); expect(actionsClientLlm._call(prompt)).rejects.toThrowError( - 'ActionsClientLlm: choices is expected to be an non-empty array' + 'ActionsClientLlm: content should be a string, but it had an unexpected type: number' ); }); }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts index 78cc3caf543547..8b7715e790e462 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/llm/actions_client_llm.ts @@ -11,6 +11,7 @@ import { LLM } from 'langchain/llms/base'; import { get } from 'lodash/fp'; import { getMessageContentAndRole } from '../helpers'; +import { RequestBody } from '../types'; const LLM_TYPE = 'ActionsClientLlm'; @@ -18,10 +19,8 @@ export class ActionsClientLlm extends LLM { #actions: ActionsPluginStart; #connectorId: string; #logger: Logger; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - #request: KibanaRequest; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - #actionResultData: Record; + #request: KibanaRequest; + #actionResultData: string; constructor({ actions, @@ -32,8 +31,7 @@ export class ActionsClientLlm extends LLM { actions: ActionsPluginStart; connectorId: string; logger: Logger; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - request: KibanaRequest; + request: KibanaRequest; }) { super({}); @@ -41,11 +39,10 @@ export class ActionsClientLlm extends LLM { this.#connectorId = connectorId; this.#logger = logger; this.#request = request; - this.#actionResultData = {}; + this.#actionResultData = ''; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getActionResultData(): Record { + getActionResultData(): string { return this.#actionResultData; } @@ -59,7 +56,6 @@ export class ActionsClientLlm extends LLM { this.#logger.debug( `ActionsClientLlm#_call assistantMessage:\n ${JSON.stringify(assistantMessage)} ` ); - // create a new connector request body with the assistant message: const requestBody = { actionId: this.#connectorId, @@ -67,7 +63,7 @@ export class ActionsClientLlm extends LLM { ...this.#request.body.params, // the original request body params subActionParams: { ...this.#request.body.params.subActionParams, // the original request body params.subActionParams - body: JSON.stringify({ messages: [assistantMessage] }), + messages: [assistantMessage], // the assistant message }, }, }; @@ -83,24 +79,16 @@ export class ActionsClientLlm extends LLM { ); } - const choices = get('data.choices', actionResult); - - if (Array.isArray(choices) && choices.length > 0) { - // get the raw content from the first choice, because _call must return a string - const content: string | undefined = choices[0]?.message?.content; - - if (typeof content !== 'string') { - throw new Error( - `${LLM_TYPE}: choices[0] message content should be a string, but it had an unexpected type: ${typeof content}` - ); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.#actionResultData = actionResult.data as Record; // save the raw response from the connector, because that's what the assistant expects + // TODO: handle errors from the connector + const content = get('data', actionResult); - return content; // per the contact of _call, return a string - } else { - throw new Error(`${LLM_TYPE}: choices is expected to be an non-empty array`); + if (typeof content !== 'string') { + throw new Error( + `${LLM_TYPE}: content should be a string, but it had an unexpected type: ${typeof content}` + ); } + this.#actionResultData = content; // save the raw response from the connector, because that's what the assistant expects + + return content; // per the contact of _call, return a string } } diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts new file mode 100644 index 00000000000000..620f2554ecf436 --- /dev/null +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/types.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PostActionsConnectorExecuteBodyInputs } from '../../schemas/post_actions_connector_execute'; + +export type RequestBody = PostActionsConnectorExecuteBodyInputs; + +export interface ResponseBody { + status: string; + data: string; + connector_id: string; +} 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 57f2b25f5a65fa..df5147bb5bec59 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 @@ -9,7 +9,7 @@ import { ElasticsearchClient, IRouter, KibanaRequest, Logger } from '@kbn/core/s import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server'; import { BaseMessage } from 'langchain/schema'; -import { mockActionResultData } from '../__mocks__/action_result_data'; +import { mockActionResponse } from '../__mocks__/action_result_data'; import { postActionsConnectorExecuteRoute } from './post_actions_connector_execute'; import { ElasticAssistantRequestHandlerContext } from '../types'; import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; @@ -35,7 +35,7 @@ jest.mock('../lib/langchain/execute_custom_llm_chain', () => ({ if (connectorId === 'mock-connector-id') { return { connector_id: 'mock-connector-id', - data: mockActionResultData, + data: mockActionResponse, status: 'ok', }; } else { @@ -62,9 +62,23 @@ const mockRequest = { body: { params: { subActionParams: { - body: '{"messages":[{"role":"user","content":"\\n\\n\\n\\nWhat is my name?"},{"role":"assistant","content":"I\'m sorry, but I don\'t have the information about your name. You can tell me your name if you\'d like, and we can continue our conversation from there."},{"role":"user","content":"\\n\\nMy name is Andrew"},{"role":"assistant","content":"Hello, Andrew! It\'s nice to meet you. What would you like to talk about today?"},{"role":"user","content":"\\n\\nDo you know my name?"}]}', + messages: [ + { role: 'user', content: '\\n\\n\\n\\nWhat is my name?' }, + { + role: 'assistant', + content: + "I'm sorry, but I don't have the information about your name. You can tell me your name if you'd like, and we can continue our conversation from there.", + }, + { role: 'user', content: '\\n\\nMy name is Andrew' }, + { + role: 'assistant', + content: + "Hello, Andrew! It's nice to meet you. What would you like to talk about today?", + }, + { role: 'user', content: '\\n\\nDo you know my name?' }, + ], }, - subAction: 'test', + subAction: 'invokeAI', }, }, }; @@ -87,7 +101,7 @@ describe('postActionsConnectorExecuteRoute', () => { expect(result).toEqual({ body: { connector_id: 'mock-connector-id', - data: mockActionResultData, + data: mockActionResponse, status: 'ok', }, }); 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 bbb1c76e3e5799..0ff90c5fa3ca6f 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 @@ -9,10 +9,7 @@ import { IRouter, Logger } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { POST_ACTIONS_CONNECTOR_EXECUTE } from '../../common/constants'; -import { - getLangChainMessages, - unsafeGetAssistantMessagesFromRequest, -} from '../lib/langchain/helpers'; +import { getLangChainMessages } from '../lib/langchain/helpers'; import { buildResponse } from '../lib/build_response'; import { buildRouteValidation } from '../schemas/common'; import { @@ -39,7 +36,6 @@ export const postActionsConnectorExecuteRoute = ( try { const connectorId = decodeURIComponent(request.params.connectorId); - const rawSubActionParamsBody = request.body.params.subActionParams.body; // get the actions plugin start contract from the request context: const actions = (await context.elasticAssistant).actions; @@ -47,11 +43,10 @@ export const postActionsConnectorExecuteRoute = ( // get a scoped esClient for assistant memory const esClient = (await context.core).elasticsearch.client.asCurrentUser; - // get the assistant messages from the request body: - const assistantMessages = unsafeGetAssistantMessagesFromRequest(rawSubActionParamsBody); - // convert the assistant messages to LangChain messages: - const langChainMessages = getLangChainMessages(assistantMessages); + const langChainMessages = getLangChainMessages( + request.body.params.subActionParams.messages + ); const langChainResponseBody = await callAgentExecutor({ actions, diff --git a/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts b/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts index 0aae23ed7512dc..b30ccd94e105b1 100644 --- a/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts +++ b/x-pack/plugins/elastic_assistant/server/schemas/post_actions_connector_execute.ts @@ -15,9 +15,23 @@ export const PostActionsConnectorExecutePathParams = t.type({ /** Validates the body of a POST request to the `/actions/connector/{connector_id}/_execute` endpoint */ export const PostActionsConnectorExecuteBody = t.type({ params: t.type({ - subActionParams: t.type({ - body: t.string, - }), + subActionParams: t.intersection([ + t.type({ + messages: t.array( + t.type({ + // must match ConversationRole from '@kbn/elastic-assistant + role: t.union([t.literal('system'), t.literal('user'), t.literal('assistant')]), + content: t.string, + }) + ), + }), + t.partial({ + model: t.string, + n: t.number, + stop: t.union([t.string, t.array(t.string), t.null]), + temperature: t.number, + }), + ]), subAction: t.string, }), }); diff --git a/x-pack/plugins/stack_connectors/common/bedrock/constants.ts b/x-pack/plugins/stack_connectors/common/bedrock/constants.ts new file mode 100644 index 00000000000000..d21515ead833f3 --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/bedrock/constants.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 { i18n } from '@kbn/i18n'; + +export const BEDROCK_TITLE = i18n.translate( + 'xpack.stackConnectors.components.bedrock.connectorTypeTitle', + { + defaultMessage: 'AWS Bedrock', + } +); +export const BEDROCK_CONNECTOR_ID = '.bedrock'; +export enum SUB_ACTION { + RUN = 'run', + INVOKE_AI = 'invokeAI', + TEST = 'test', +} + +export const DEFAULT_BEDROCK_MODEL = 'anthropic.claude-v2'; + +export const DEFAULT_BEDROCK_URL = `https://bedrock.us-east-1.amazonaws.com` as const; diff --git a/x-pack/plugins/stack_connectors/common/bedrock/schema.ts b/x-pack/plugins/stack_connectors/common/bedrock/schema.ts new file mode 100644 index 00000000000000..ac23ed9667ada6 --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/bedrock/schema.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { DEFAULT_BEDROCK_MODEL } from './constants'; + +// Connector schema +export const ConfigSchema = schema.object({ + apiUrl: schema.string(), + defaultModel: schema.string({ defaultValue: DEFAULT_BEDROCK_MODEL }), +}); + +export const SecretsSchema = schema.object({ + accessKey: schema.string(), + secret: schema.string(), +}); + +export const RunActionParamsSchema = schema.object({ + body: schema.string(), + model: schema.maybe(schema.string()), +}); + +export const InvokeAIActionParamsSchema = schema.object({ + messages: schema.arrayOf( + schema.object({ + role: schema.string(), + content: schema.string(), + }) + ), + model: schema.maybe(schema.string()), +}); + +export const InvokeAIActionResponseSchema = schema.string(); + +export const RunActionResponseSchema = schema.object( + { + completion: schema.string(), + stop_reason: schema.maybe(schema.string()), + }, + { unknowns: 'ignore' } +); diff --git a/x-pack/plugins/stack_connectors/common/bedrock/types.ts b/x-pack/plugins/stack_connectors/common/bedrock/types.ts new file mode 100644 index 00000000000000..c6fad07cdba37c --- /dev/null +++ b/x-pack/plugins/stack_connectors/common/bedrock/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. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { + ConfigSchema, + SecretsSchema, + RunActionParamsSchema, + RunActionResponseSchema, + InvokeAIActionParamsSchema, + InvokeAIActionResponseSchema, +} from './schema'; + +export type Config = TypeOf; +export type Secrets = TypeOf; +export type RunActionParams = TypeOf; +export type InvokeAIActionParams = TypeOf; +export type InvokeAIActionResponse = TypeOf; +export type RunActionResponse = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/gen_ai/constants.ts b/x-pack/plugins/stack_connectors/common/gen_ai/constants.ts index 6e3d2924ca6c7a..8c8dd84c4e326a 100644 --- a/x-pack/plugins/stack_connectors/common/gen_ai/constants.ts +++ b/x-pack/plugins/stack_connectors/common/gen_ai/constants.ts @@ -7,15 +7,16 @@ import { i18n } from '@kbn/i18n'; -export const GEN_AI_TITLE = i18n.translate( +export const OPEN_AI_TITLE = i18n.translate( 'xpack.stackConnectors.components.genAi.connectorTypeTitle', { - defaultMessage: 'Generative AI', + defaultMessage: 'OpenAI', } ); export const GEN_AI_CONNECTOR_ID = '.gen-ai'; export enum SUB_ACTION { RUN = 'run', + INVOKE_AI = 'invokeAI', STREAM = 'stream', DASHBOARD = 'getDashboard', TEST = 'test', diff --git a/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts b/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts index f82b89ee7c2b6f..fa14aa61fa5b36 100644 --- a/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts +++ b/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { DEFAULT_OPENAI_MODEL, OpenAiProviderType } from './constants'; // Connector schema -export const GenAiConfigSchema = schema.oneOf([ +export const ConfigSchema = schema.oneOf([ schema.object({ apiProvider: schema.oneOf([schema.literal(OpenAiProviderType.AzureAi)]), apiUrl: schema.string(), @@ -21,22 +21,40 @@ export const GenAiConfigSchema = schema.oneOf([ }), ]); -export const GenAiSecretsSchema = schema.object({ apiKey: schema.string() }); +export const SecretsSchema = schema.object({ apiKey: schema.string() }); // Run action schema -export const GenAiRunActionParamsSchema = schema.object({ +export const RunActionParamsSchema = schema.object({ body: schema.string(), }); +// Run action schema +export const InvokeAIActionParamsSchema = schema.object({ + messages: schema.arrayOf( + schema.object({ + role: schema.string(), + content: schema.string(), + }) + ), + model: schema.maybe(schema.string()), + n: schema.maybe(schema.number()), + stop: schema.maybe( + schema.nullable(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])) + ), + temperature: schema.maybe(schema.number()), +}); + +export const InvokeAIActionResponseSchema = schema.string(); + // Execute action schema -export const GenAiStreamActionParamsSchema = schema.object({ +export const StreamActionParamsSchema = schema.object({ body: schema.string(), stream: schema.boolean({ defaultValue: false }), }); -export const GenAiStreamingResponseSchema = schema.any(); +export const StreamingResponseSchema = schema.any(); -export const GenAiRunActionResponseSchema = schema.object( +export const RunActionResponseSchema = schema.object( { id: schema.maybe(schema.string()), object: schema.maybe(schema.string()), @@ -71,10 +89,10 @@ export const GenAiRunActionResponseSchema = schema.object( ); // Run action schema -export const GenAiDashboardActionParamsSchema = schema.object({ +export const DashboardActionParamsSchema = schema.object({ dashboardId: schema.string(), }); -export const GenAiDashboardActionResponseSchema = schema.object({ +export const DashboardActionResponseSchema = schema.object({ available: schema.boolean(), }); diff --git a/x-pack/plugins/stack_connectors/common/gen_ai/types.ts b/x-pack/plugins/stack_connectors/common/gen_ai/types.ts index 688a577a90f488..86e2c172846dc0 100644 --- a/x-pack/plugins/stack_connectors/common/gen_ai/types.ts +++ b/x-pack/plugins/stack_connectors/common/gen_ai/types.ts @@ -7,19 +7,23 @@ import { TypeOf } from '@kbn/config-schema'; import { - GenAiConfigSchema, - GenAiSecretsSchema, - GenAiRunActionParamsSchema, - GenAiRunActionResponseSchema, - GenAiDashboardActionParamsSchema, - GenAiDashboardActionResponseSchema, - GenAiStreamActionParamsSchema, + ConfigSchema, + SecretsSchema, + RunActionParamsSchema, + RunActionResponseSchema, + DashboardActionParamsSchema, + DashboardActionResponseSchema, + StreamActionParamsSchema, + InvokeAIActionParamsSchema, + InvokeAIActionResponseSchema, } from './schema'; -export type GenAiConfig = TypeOf; -export type GenAiSecrets = TypeOf; -export type GenAiRunActionParams = TypeOf; -export type GenAiRunActionResponse = TypeOf; -export type GenAiDashboardActionParams = TypeOf; -export type GenAiDashboardActionResponse = TypeOf; -export type GenAiStreamActionParams = TypeOf; +export type Config = TypeOf; +export type Secrets = TypeOf; +export type RunActionParams = TypeOf; +export type InvokeAIActionParams = TypeOf; +export type InvokeAIActionResponse = TypeOf; +export type RunActionResponse = TypeOf; +export type DashboardActionParams = TypeOf; +export type DashboardActionResponse = TypeOf; +export type StreamActionParams = TypeOf; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.test.tsx new file mode 100644 index 00000000000000..d823633f84585e --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.test.tsx @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TypeRegistry } from '@kbn/triggers-actions-ui-plugin/public/application/type_registry'; +import { registerConnectorTypes } from '..'; +import type { ActionTypeModel } from '@kbn/triggers-actions-ui-plugin/public/types'; +import { registrationServicesMock } from '../../mocks'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; + +const ACTION_TYPE_ID = '.bedrock'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const connectorTypeRegistry = new TypeRegistry(); + registerConnectorTypes({ connectorTypeRegistry, services: registrationServicesMock }); + const getResult = connectorTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('connector type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.selectMessage).toBe('Send a request to AWS Bedrock systems.'); + expect(actionTypeModel.actionTypeTitle).toBe('AWS Bedrock'); + }); +}); + +describe('bedrock action params validation', () => { + test('action params validation succeeds when action params is valid', async () => { + const actionParams = { + subAction: SUB_ACTION.RUN, + subActionParams: { body: '{"message": "test"}' }, + }; + + expect(await actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { body: [], subAction: [] }, + }); + }); + + test('params validation fails when body is not an object', async () => { + const actionParams = { + subAction: SUB_ACTION.RUN, + subActionParams: { body: 'message {test}' }, + }; + + expect(await actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { body: ['Body does not have a valid JSON format.'], subAction: [] }, + }); + }); + + test('params validation fails when subAction is missing', async () => { + const actionParams = { + subActionParams: { body: '{"message": "test"}' }, + }; + + expect(await actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + body: [], + subAction: ['Action is required.'], + }, + }); + }); + + test('params validation fails when subActionParams is missing', async () => { + const actionParams = { + subAction: SUB_ACTION.RUN, + subActionParams: {}, + }; + + expect(await actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + body: ['Body is required.'], + subAction: [], + }, + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx new file mode 100644 index 00000000000000..1bc6febe04b09a --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/bedrock.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { lazy } from 'react'; +import { i18n } from '@kbn/i18n'; +import type { GenericValidationResult } from '@kbn/triggers-actions-ui-plugin/public/types'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; +import { BEDROCK_CONNECTOR_ID, BEDROCK_TITLE } from '../../../common/bedrock/constants'; +import { BedrockActionParams, BedrockConnector } from './types'; + +interface ValidationErrors { + subAction: string[]; + body: string[]; +} +export function getConnectorType(): BedrockConnector { + return { + id: BEDROCK_CONNECTOR_ID, + iconClass: lazy(() => import('./logo')), + selectMessage: i18n.translate('xpack.stackConnectors.components.bedrock.selectMessageText', { + defaultMessage: 'Send a request to AWS Bedrock systems.', + }), + actionTypeTitle: BEDROCK_TITLE, + validateParams: async ( + actionParams: BedrockActionParams + ): Promise> => { + const { subAction, subActionParams } = actionParams; + const translations = await import('./translations'); + const errors: ValidationErrors = { + body: [], + subAction: [], + }; + + if (subAction === SUB_ACTION.TEST || subAction === SUB_ACTION.RUN) { + if (!subActionParams.body?.length) { + errors.body.push(translations.BODY_REQUIRED); + } else { + try { + JSON.parse(subActionParams.body); + } catch { + errors.body.push(translations.BODY_INVALID); + } + } + } + if (errors.body.length) return { errors }; + + // The internal "subAction" param should always be valid, ensure it is only if "subActionParams" are valid + if (!subAction) { + errors.subAction.push(translations.ACTION_REQUIRED); + } else if (subAction !== SUB_ACTION.RUN && subAction !== SUB_ACTION.TEST) { + errors.subAction.push(translations.INVALID_ACTION); + } + return { errors }; + }, + actionConnectorFields: lazy(() => import('./connector')), + actionParamsFields: lazy(() => import('./params')), + }; +} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx new file mode 100644 index 00000000000000..063d0e39d7ef94 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.test.tsx @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import BedrockConnectorFields from './connector'; +import { ConnectorFormTestProvider } from '../lib/test_utils'; +import { act, render, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; +import { DEFAULT_BEDROCK_MODEL } from '../../../common/bedrock/constants'; + +jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); +const useKibanaMock = useKibana as jest.Mocked; +const bedrockConnector = { + actionTypeId: '.bedrock', + name: 'bedrock', + id: '123', + config: { + apiUrl: 'https://bedrockurl.com', + defaultModel: DEFAULT_BEDROCK_MODEL, + }, + secrets: { + accessKey: 'thats-a-nice-looking-key', + secret: 'thats-a-nice-looking-secret', + }, + isDeprecated: false, +}; + +const navigateToUrl = jest.fn(); + +describe('BedrockConnectorFields renders', () => { + beforeEach(() => { + jest.clearAllMocks(); + useKibanaMock().services.application.navigateToUrl = navigateToUrl; + }); + test('Bedrock connector fields are rendered', async () => { + const { getAllByTestId } = render( + + {}} + /> + + ); + + expect(getAllByTestId('config.apiUrl-input')[0]).toBeInTheDocument(); + expect(getAllByTestId('config.apiUrl-input')[0]).toHaveValue(bedrockConnector.config.apiUrl); + expect(getAllByTestId('config.defaultModel-input')[0]).toBeInTheDocument(); + expect(getAllByTestId('config.defaultModel-input')[0]).toHaveValue( + bedrockConnector.config.defaultModel + ); + expect(getAllByTestId('bedrock-api-doc')[0]).toBeInTheDocument(); + expect(getAllByTestId('bedrock-api-model-doc')[0]).toBeInTheDocument(); + }); + + describe('Validation', () => { + const onSubmit = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('connector validation succeeds when connector config is valid', async () => { + const { getByTestId } = render( + + {}} + /> + + ); + + await act(async () => { + userEvent.click(getByTestId('form-test-provide-submit')); + }); + + await waitFor(async () => { + expect(onSubmit).toHaveBeenCalled(); + }); + + expect(onSubmit).toBeCalledWith({ + data: bedrockConnector, + isValid: true, + }); + }); + + it('validates correctly if the apiUrl is empty', async () => { + const connector = { + ...bedrockConnector, + config: { + ...bedrockConnector.config, + apiUrl: '', + }, + }; + + const res = render( + + {}} + /> + + ); + + await act(async () => { + userEvent.click(res.getByTestId('form-test-provide-submit')); + }); + await waitFor(async () => { + expect(onSubmit).toHaveBeenCalled(); + }); + + expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + }); + + const tests: Array<[string, string]> = [ + ['config.apiUrl-input', 'not-valid'], + ['secrets.accessKey-input', ''], + ]; + it.each(tests)('validates correctly %p', async (field, value) => { + const connector = { + ...bedrockConnector, + config: { + ...bedrockConnector.config, + headers: [], + }, + }; + + const res = render( + + {}} + /> + + ); + + await act(async () => { + await userEvent.type(res.getByTestId(field), `{selectall}{backspace}${value}`, { + delay: 10, + }); + }); + + await act(async () => { + userEvent.click(res.getByTestId('form-test-provide-submit')); + }); + await waitFor(async () => { + expect(onSubmit).toHaveBeenCalled(); + }); + + expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx new file mode 100644 index 00000000000000..c99574aaf5c431 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/connector.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + ActionConnectorFieldsProps, + SimpleConnectorForm, +} from '@kbn/triggers-actions-ui-plugin/public'; +import { bedrockConfig, bedrockSecrets } from './constants'; + +const BedrockConnectorFields: React.FC = ({ readOnly, isEdit }) => { + return ( + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { BedrockConnectorFields as default }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/constants.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/constants.tsx new file mode 100644 index 00000000000000..18c635c41369f5 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/constants.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { ConfigFieldSchema, SecretsFieldSchema } from '@kbn/triggers-actions-ui-plugin/public'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiLink } from '@elastic/eui'; +import { DEFAULT_BEDROCK_MODEL, DEFAULT_BEDROCK_URL } from '../../../common/bedrock/constants'; +import * as i18n from './translations'; + +const human = '\n\nHuman:'; +const assistant = '\n\nAssistant:'; + +export const DEFAULT_BODY = JSON.stringify({ + prompt: `${human} Hello world! ${assistant}`, + max_tokens_to_sample: 300, + stop_sequences: [human], +}); + +export const bedrockConfig: ConfigFieldSchema[] = [ + { + id: 'apiUrl', + label: i18n.API_URL_LABEL, + isUrlField: true, + defaultValue: DEFAULT_BEDROCK_URL, + helpText: ( + + {`${i18n.BEDROCK} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + }, + { + id: 'defaultModel', + label: i18n.DEFAULT_MODEL_LABEL, + helpText: ( + + {`${i18n.BEDROCK} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + defaultValue: DEFAULT_BEDROCK_MODEL, + }, +]; + +export const bedrockSecrets: SecretsFieldSchema[] = [ + { + id: 'accessKey', + label: i18n.ACCESS_KEY_LABEL, + isPasswordField: true, + helpText: ( + + {`${i18n.BEDROCK} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + }, + { + id: 'secret', + label: i18n.SECRET, + isPasswordField: true, + helpText: ( + + {`${i18n.BEDROCK} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + ), + }, +]; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/index.ts b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/index.ts new file mode 100644 index 00000000000000..95c03f880277d1 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getConnectorType as getBedrockConnectorType } from './bedrock'; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/logo.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/logo.tsx new file mode 100644 index 00000000000000..68b385b4b246e4 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/logo.tsx @@ -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 React from 'react'; +import { LogoProps } from '../types'; + +const Logo = (props: LogoProps) => ( + + + +); + +// eslint-disable-next-line import/no-default-export +export { Logo as default }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.test.tsx new file mode 100644 index 00000000000000..893c513b6f3958 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.test.tsx @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import BedrockParamsFields from './params'; +import { MockCodeEditor } from '@kbn/triggers-actions-ui-plugin/public/application/code_editor.mock'; +import { DEFAULT_BEDROCK_URL, SUB_ACTION } from '../../../common/bedrock/constants'; +import { I18nProvider } from '@kbn/i18n-react'; + +const kibanaReactPath = '../../../../../../src/plugins/kibana_react/public'; + +jest.mock(kibanaReactPath, () => { + const original = jest.requireActual(kibanaReactPath); + return { + ...original, + CodeEditor: (props: any) => { + return ; + }, + }; +}); +const messageVariables = [ + { + name: 'myVar', + description: 'My variable description', + useWithTripleBracesInTemplates: true, + }, +]; + +describe('Bedrock Params Fields renders', () => { + test('all params fields are rendered', () => { + const { getByTestId } = render( + {}} + index={0} + messageVariables={messageVariables} + />, + { + wrapper: ({ children }) => {children}, + } + ); + expect(getByTestId('bodyJsonEditor')).toBeInTheDocument(); + expect(getByTestId('bodyJsonEditor')).toHaveProperty('value', '{"message": "test"}'); + expect(getByTestId('bodyAddVariableButton')).toBeInTheDocument(); + expect(getByTestId('bedrock-model')).toBeInTheDocument(); + }); + test('useEffect handles the case when subAction and subActionParams are undefined', () => { + const actionParams = { + subAction: undefined, + subActionParams: undefined, + }; + const editAction = jest.fn(); + const errors = {}; + const actionConnector = { + secrets: { + accessKey: 'accessKey', + secret: 'secret', + }, + id: 'test', + actionTypeId: '.bedrock', + isPreconfigured: false, + isSystemAction: false as const, + isDeprecated: false, + name: 'My Bedrock Connector', + config: { + apiUrl: DEFAULT_BEDROCK_URL, + }, + }; + render( + , + { + wrapper: ({ children }) => {children}, + } + ); + expect(editAction).toHaveBeenCalledTimes(2); + expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.RUN, 0); + }); + + it('handles the case when subAction only is undefined', () => { + const actionParams = { + subAction: undefined, + subActionParams: { + body: '{"key": "value"}', + }, + }; + const editAction = jest.fn(); + const errors = {}; + render( + , + { + wrapper: ({ children }) => {children}, + } + ); + expect(editAction).toHaveBeenCalledTimes(1); + expect(editAction).toHaveBeenCalledWith('subAction', SUB_ACTION.RUN, 0); + }); + + it('calls editAction function with the body argument', () => { + const editAction = jest.fn(); + const errors = {}; + const { getByTestId } = render( + , + { + wrapper: ({ children }) => {children}, + } + ); + const jsonEditor = getByTestId('bodyJsonEditor'); + fireEvent.change(jsonEditor, { target: { value: '{"new_key": "new_value"}' } }); + expect(editAction).toHaveBeenCalledWith( + 'subActionParams', + { body: '{"new_key": "new_value"}' }, + 0 + ); + }); + + it('calls editAction function with the model argument', () => { + const editAction = jest.fn(); + const errors = {}; + const { getByTestId } = render( + , + { + wrapper: ({ children }) => {children}, + } + ); + const model = getByTestId('bedrock-model'); + fireEvent.change(model, { target: { value: 'not-the-default' } }); + expect(editAction).toHaveBeenCalledWith( + 'subActionParams', + { body: '{"key": "value"}', model: 'not-the-default' }, + 0 + ); + }); +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.tsx new file mode 100644 index 00000000000000..b880e388b9f910 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/params.tsx @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useMemo } from 'react'; +import type { ActionParamsProps } from '@kbn/triggers-actions-ui-plugin/public'; +import { + ActionConnectorMode, + JsonEditorWithMessageVariables, +} from '@kbn/triggers-actions-ui-plugin/public'; +import { EuiFieldText, EuiFormRow, EuiLink } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import * as i18n from './translations'; +import { DEFAULT_BODY } from './constants'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; +import { BedrockActionParams } from './types'; + +const BedrockParamsFields: React.FunctionComponent> = ({ + actionParams, + editAction, + index, + messageVariables, + executionMode, + errors, +}) => { + const { subAction, subActionParams } = actionParams; + + const { body, model } = subActionParams ?? {}; + + const isTest = useMemo(() => executionMode === ActionConnectorMode.Test, [executionMode]); + + useEffect(() => { + if (!subAction) { + editAction('subAction', isTest ? SUB_ACTION.TEST : SUB_ACTION.RUN, index); + } + }, [editAction, index, isTest, subAction]); + + useEffect(() => { + if (!subActionParams) { + editAction('subActionParams', { body: DEFAULT_BODY }, index); + } + }, [editAction, index, subActionParams]); + + useEffect(() => { + return () => { + // some bedrock specific formatting gets messed up if we do not reset + // subActionParams on dismount (switching tabs between test and config) + editAction('subActionParams', undefined, index); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const editSubActionParams = useCallback( + (params: Partial) => { + editAction('subActionParams', { ...subActionParams, ...params }, index); + }, + [editAction, index, subActionParams] + ); + + return ( + <> + { + editSubActionParams({ body: json }); + }} + onBlur={() => { + if (!body) { + editSubActionParams({ body: '' }); + } + }} + data-test-subj="bedrock-bodyJsonEditor" + /> + + {`${i18n.BEDROCK} ${i18n.DOCUMENTATION}`} + + ), + }} + /> + } + > + { + editSubActionParams({ model: ev.target.value }); + }} + fullWidth + /> + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { BedrockParamsFields as default }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts new file mode 100644 index 00000000000000..37c8165b76048c --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/translations.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const API_URL_LABEL = i18n.translate( + 'xpack.stackConnectors.components.bedrock.apiUrlTextFieldLabel', + { + defaultMessage: 'URL', + } +); + +export const ACCESS_KEY_LABEL = i18n.translate( + 'xpack.stackConnectors.components.bedrock.accessKeySecret', + { + defaultMessage: 'Access Key', + } +); + +export const DEFAULT_MODEL_LABEL = i18n.translate( + 'xpack.stackConnectors.components.bedrock.defaultModelTextFieldLabel', + { + defaultMessage: 'Default model', + } +); + +export const REGION_LABEL = i18n.translate( + 'xpack.stackConnectors.components.bedrock.defaultRegionTextFieldLabel', + { + defaultMessage: 'AWS Region', + } +); + +export const SECRET = i18n.translate('xpack.stackConnectors.components.bedrock.secret', { + defaultMessage: 'Secret', +}); + +export const BEDROCK = i18n.translate('xpack.stackConnectors.components.bedrock.title', { + defaultMessage: 'AWS Bedrock', +}); + +export const DOCUMENTATION = i18n.translate( + 'xpack.stackConnectors.components.bedrock.documentation', + { + defaultMessage: 'documentation', + } +); + +export const URL_LABEL = i18n.translate( + 'xpack.stackConnectors.components.bedrock.urlTextFieldLabel', + { + defaultMessage: 'URL', + } +); + +export const BODY_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.bedrock.error.requiredBedrockBodyText', + { + defaultMessage: 'Body is required.', + } +); +export const BODY_INVALID = i18n.translate( + 'xpack.stackConnectors.security.bedrock.params.error.invalidBodyText', + { + defaultMessage: 'Body does not have a valid JSON format.', + } +); + +export const ACTION_REQUIRED = i18n.translate( + 'xpack.stackConnectors.security.bedrock.params.error.requiredActionText', + { + defaultMessage: 'Action is required.', + } +); + +export const INVALID_ACTION = i18n.translate( + 'xpack.stackConnectors.security.bedrock.params.error.invalidActionText', + { + defaultMessage: 'Invalid action name.', + } +); + +export const BODY = i18n.translate('xpack.stackConnectors.components.bedrock.bodyFieldLabel', { + defaultMessage: 'Body', +}); +export const BODY_DESCRIPTION = i18n.translate( + 'xpack.stackConnectors.components.bedrock.bodyCodeEditorAriaLabel', + { + defaultMessage: 'Code editor', + } +); + +export const MODEL = i18n.translate('xpack.stackConnectors.components.bedrock.model', { + defaultMessage: 'Model', +}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/bedrock/types.ts b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/types.ts new file mode 100644 index 00000000000000..db766ea562a515 --- /dev/null +++ b/x-pack/plugins/stack_connectors/public/connector_types/bedrock/types.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionTypeModel as ConnectorTypeModel } from '@kbn/triggers-actions-ui-plugin/public'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; +import { RunActionParams } from '../../../common/bedrock/types'; + +export interface BedrockActionParams { + subAction: SUB_ACTION.RUN | SUB_ACTION.TEST; + subActionParams: RunActionParams; +} + +export interface Config { + apiUrl: string; + defaultModel: string; +} + +export interface Secrets { + accessKey: string; + secret: string; +} + +export type BedrockConnector = ConnectorTypeModel; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.test.tsx index efa0d5ce82fe75..3bed686dca0255 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.test.tsx @@ -27,7 +27,7 @@ describe('actionTypeRegistry.get() works', () => { test('connector type static data is as expected', () => { expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); expect(actionTypeModel.selectMessage).toBe('Send a request to generative AI systems.'); - expect(actionTypeModel.actionTypeTitle).toBe('Generative AI'); + expect(actionTypeModel.actionTypeTitle).toBe('OpenAI'); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.tsx b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.tsx index b326d59cc9c645..7a4c798763c46d 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/gen_ai.tsx @@ -9,7 +9,7 @@ import { lazy } from 'react'; import { i18n } from '@kbn/i18n'; import type { GenericValidationResult } from '@kbn/triggers-actions-ui-plugin/public/types'; import { SUB_ACTION } from '../../../common/gen_ai/constants'; -import { GEN_AI_CONNECTOR_ID, GEN_AI_TITLE } from '../../../common/gen_ai/constants'; +import { GEN_AI_CONNECTOR_ID, OPEN_AI_TITLE } from '../../../common/gen_ai/constants'; import { GenerativeAiActionParams, GenerativeAiConnector } from './types'; interface ValidationErrors { @@ -23,7 +23,7 @@ export function getConnectorType(): GenerativeAiConnector { selectMessage: i18n.translate('xpack.stackConnectors.components.genAi.selectMessageText', { defaultMessage: 'Send a request to generative AI systems.', }), - actionTypeTitle: GEN_AI_TITLE, + actionTypeTitle: OPEN_AI_TITLE, validateParams: async ( actionParams: GenerativeAiActionParams ): Promise> => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/types.ts b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/types.ts index d86508c750bcee..ddb0f8e871b197 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/types.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/gen_ai/types.ts @@ -8,11 +8,11 @@ import { ActionTypeModel as ConnectorTypeModel } from '@kbn/triggers-actions-ui-plugin/public'; import { UserConfiguredActionConnector } from '@kbn/triggers-actions-ui-plugin/public/types'; import { OpenAiProviderType, SUB_ACTION } from '../../../common/gen_ai/constants'; -import { GenAiRunActionParams } from '../../../common/gen_ai/types'; +import { RunActionParams } from '../../../common/gen_ai/types'; export interface GenerativeAiActionParams { subAction: SUB_ACTION.RUN | SUB_ACTION.TEST; - subActionParams: GenAiRunActionParams; + subActionParams: RunActionParams; } export interface GenerativeAiConfig { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/index.ts b/x-pack/plugins/stack_connectors/public/connector_types/index.ts index abc018631db7a1..20964012607f80 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/index.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/index.ts @@ -12,6 +12,7 @@ import { getEmailConnectorType } from './email'; import { getIndexConnectorType } from './es_index'; import { getJiraConnectorType } from './jira'; import { getGenerativeAiConnectorType } from './gen_ai'; +import { getBedrockConnectorType } from './bedrock'; import { getOpsgenieConnectorType } from './opsgenie'; import { getPagerDutyConnectorType } from './pagerduty'; import { getResilientConnectorType } from './resilient'; @@ -60,6 +61,7 @@ export function registerConnectorTypes({ connectorTypeRegistry.register(getResilientConnectorType()); connectorTypeRegistry.register(getOpsgenieConnectorType()); connectorTypeRegistry.register(getGenerativeAiConnectorType()); + connectorTypeRegistry.register(getBedrockConnectorType()); connectorTypeRegistry.register(getTeamsConnectorType()); connectorTypeRegistry.register(getTorqConnectorType()); connectorTypeRegistry.register(getTinesConnectorType()); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts new file mode 100644 index 00000000000000..919c4303c4f66a --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -0,0 +1,155 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BedrockConnector } from './bedrock'; +import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { actionsMock } from '@kbn/actions-plugin/server/mocks'; +import { RunActionResponseSchema } from '../../../common/bedrock/schema'; +import { + BEDROCK_CONNECTOR_ID, + DEFAULT_BEDROCK_MODEL, + DEFAULT_BEDROCK_URL, +} from '../../../common/bedrock/constants'; +import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; + +jest.mock('aws4', () => ({ + sign: () => ({ signed: true }), +})); + +describe('BedrockConnector', () => { + let mockRequest: jest.Mock; + let mockError: jest.Mock; + const mockResponseString = 'Hello! How can I assist you today?'; + const mockResponse = { + headers: {}, + data: { + completion: mockResponseString, + stop_reason: 'stop_sequence', + }, + }; + beforeEach(() => { + mockRequest = jest.fn().mockResolvedValue(mockResponse); + mockError = jest.fn().mockImplementation(() => { + throw new Error('API Error'); + }); + }); + + describe('Bedrock', () => { + const connector = new BedrockConnector({ + configurationUtilities: actionsConfigMock.create(), + connector: { id: '1', type: BEDROCK_CONNECTOR_ID }, + config: { + apiUrl: DEFAULT_BEDROCK_URL, + defaultModel: DEFAULT_BEDROCK_MODEL, + }, + secrets: { accessKey: '123', secret: 'secret' }, + logger: loggingSystemMock.createLogger(), + services: actionsMock.createServices(), + }); + + beforeEach(() => { + // @ts-ignore + connector.request = mockRequest; + jest.clearAllMocks(); + }); + + describe('runApi', () => { + it('the Bedrock API call is successful with correct parameters', async () => { + const response = await connector.runApi({ body: DEFAULT_BODY }); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: DEFAULT_BODY, + }); + expect(response).toEqual(mockResponse.data); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.runApi({ body: DEFAULT_BODY })).rejects.toThrow('API Error'); + }); + }); + + describe('invokeAI', () => { + const aiAssistantBody = { + messages: [ + { + role: 'user', + content: 'Hello world', + }, + ], + }; + + it('the API call is successful with correct parameters', async () => { + const response = await connector.invokeAI(aiAssistantBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ + prompt: '\n\nHuman:Hello world \n\nAssistant:', + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'], + }), + }); + expect(response).toEqual(mockResponseString); + }); + + it('Properly formats messages from user, assistant, and system', async () => { + const response = await connector.invokeAI({ + messages: [ + { + role: 'user', + content: 'Hello world', + }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, + ], + }); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ + prompt: + '\n\nHuman:Hello world\n\nHuman:Be a good chatbot\n\nAssistant:Hi, I am a good chatbot\n\nHuman:What is 2+2? \n\nAssistant:', + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'], + }), + }); + expect(response).toEqual(mockResponseString); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.invokeAI(aiAssistantBody)).rejects.toThrow('API Error'); + }); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts new file mode 100644 index 00000000000000..5012970e4e91ca --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; +import aws from 'aws4'; +import type { AxiosError } from 'axios'; +import { + RunActionParamsSchema, + RunActionResponseSchema, + InvokeAIActionParamsSchema, +} from '../../../common/bedrock/schema'; +import type { + Config, + Secrets, + RunActionParams, + RunActionResponse, + InvokeAIActionParams, + InvokeAIActionResponse, +} from '../../../common/bedrock/types'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; + +interface SignedRequest { + host: string; + headers: Record; + body: string; + path: string; +} + +export class BedrockConnector extends SubActionConnector { + private url; + private model; + + constructor(params: ServiceParams) { + super(params); + + this.url = this.config.apiUrl; + this.model = this.config.defaultModel; + + this.registerSubActions(); + } + + private registerSubActions() { + this.registerSubAction({ + name: SUB_ACTION.RUN, + method: 'runApi', + schema: RunActionParamsSchema, + }); + + this.registerSubAction({ + name: SUB_ACTION.TEST, + method: 'runApi', + schema: RunActionParamsSchema, + }); + + this.registerSubAction({ + name: SUB_ACTION.INVOKE_AI, + method: 'invokeAI', + schema: InvokeAIActionParamsSchema, + }); + } + + protected getResponseErrorMessage(error: AxiosError<{ error?: { message?: string } }>): string { + if (!error.response?.status) { + return `Unexpected API Error: ${error.code} - ${error.message}`; + } + if (error.response.status === 401) { + return 'Unauthorized API Error'; + } + return `API Error: ${error.response?.status} - ${error.response?.statusText}${ + error.response?.data?.error?.message ? ` - ${error.response.data.error?.message}` : '' + }`; + } + + /** + * provides the AWS signature to the external API endpoint + * @param body The request body to be signed. + * @param path The path of the request URL. + */ + private signRequest(body: string, path: string) { + const { host } = new URL(this.url); + return aws.sign( + { + host, + headers: { + 'Content-Type': 'application/json', + Accept: '*/*', + }, + body, + path, + }, + { + secretAccessKey: this.secrets.secret, + accessKeyId: this.secrets.accessKey, + } + ) as SignedRequest; + } + + /** + * responsible for making a POST request to the external API endpoint and returning the response data + * @param body The stringified request body to be sent in the POST request. + * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. + */ + public async runApi({ body, model: reqModel }: RunActionParams): Promise { + // set model on per request basis + const model = reqModel ? reqModel : this.model; + const signed = this.signRequest(body, `/model/${model}/invoke`); + const response = await this.request({ + ...signed, + url: `${this.url}/model/${model}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: body, + }); + return response.data; + } + + /** + * takes in an array of messages and a model as input, and returns a promise that resolves to a string. + * The method combines the messages into a single prompt formatted for bedrock,sends a request to the + * runApi method with the prompt and model, and returns the trimmed completion from the response. + * @param messages An array of message objects, where each object has a role (string) and content (string) property. + * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. + */ + public async invokeAI({ + messages, + model, + }: InvokeAIActionParams): Promise { + const combinedMessages = messages.reduce((acc: string, message) => { + const { role, content } = message; + // Bedrock only has Assistant and Human, so 'system' and 'user' will be converted to Human + const bedrockRole = role === 'assistant' ? '\n\nAssistant:' : '\n\nHuman:'; + return `${acc}${bedrockRole}${content}`; + }, ''); + + const req = { + // end prompt in "Assistant:" to avoid the model starting its message with "Assistant:" + prompt: `${combinedMessages} \n\nAssistant:`, + max_tokens_to_sample: 300, + // prevent model from talking to itself + stop_sequences: ['\n\nHuman:'], + }; + + const res = await this.runApi({ body: JSON.stringify(req), model }); + return res.completion.trim(); + } +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.test.ts new file mode 100644 index 00000000000000..78a1937bf76c2e --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; +import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; +import axios from 'axios'; +import { configValidator, getConnectorType } from '.'; +import { Config, Secrets } from '../../../common/bedrock/types'; +import { SubActionConnectorType } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { DEFAULT_BEDROCK_MODEL } from '../../../common/bedrock/constants'; + +jest.mock('axios'); +jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { + const originalUtils = jest.requireActual('@kbn/actions-plugin/server/lib/axios_utils'); + return { + ...originalUtils, + request: jest.fn(), + patch: jest.fn(), + }; +}); + +axios.create = jest.fn(() => axios); + +let connectorType: SubActionConnectorType; +let configurationUtilities: jest.Mocked; + +describe('Bedrock Connector', () => { + beforeEach(() => { + configurationUtilities = actionsConfigMock.create(); + connectorType = getConnectorType(); + }); + test('exposes the connector as `AWS Bedrock` with id `.bedrock`', () => { + expect(connectorType.id).toEqual('.bedrock'); + expect(connectorType.name).toEqual('AWS Bedrock'); + }); + describe('config validation', () => { + test('config validation passes when only required fields are provided', () => { + const config: Config = { + apiUrl: 'https://api.openai.com/v1/chat/completions', + defaultModel: DEFAULT_BEDROCK_MODEL, + }; + + expect(configValidator(config, { configurationUtilities })).toEqual(config); + }); + + test('config validation failed when a url is invalid', () => { + const config: Config = { + apiUrl: 'example.com/do-something', + defaultModel: DEFAULT_BEDROCK_MODEL, + }; + expect(() => { + configValidator(config, { configurationUtilities }); + }).toThrowErrorMatchingInlineSnapshot( + '"Error configuring AWS Bedrock action: Error: URL Error: Invalid URL: example.com/do-something"' + ); + }); + + test('config validation returns an error if the specified URL is not added to allowedHosts', () => { + const configUtils = { + ...actionsConfigMock.create(), + ensureUriAllowed: (_: string) => { + throw new Error(`target url is not present in allowedHosts`); + }, + }; + + const config: Config = { + apiUrl: 'http://mylisteningserver.com:9200/endpoint', + defaultModel: DEFAULT_BEDROCK_MODEL, + }; + + expect(() => { + configValidator(config, { configurationUtilities: configUtils }); + }).toThrowErrorMatchingInlineSnapshot( + `"Error configuring AWS Bedrock action: Error: error validating url: target url is not present in allowedHosts"` + ); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts new file mode 100644 index 00000000000000..661771f6df1248 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/index.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { + SubActionConnectorType, + ValidatorType, +} from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { GeneralConnectorFeatureId } from '@kbn/actions-plugin/common'; +import { urlAllowListValidator } from '@kbn/actions-plugin/server'; +import { ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { assertURL } from '@kbn/actions-plugin/server/sub_action_framework/helpers/validators'; +import { BEDROCK_CONNECTOR_ID, BEDROCK_TITLE } from '../../../common/bedrock/constants'; +import { ConfigSchema, SecretsSchema } from '../../../common/bedrock/schema'; +import { Config, Secrets } from '../../../common/bedrock/types'; +import { BedrockConnector } from './bedrock'; +import { renderParameterTemplates } from './render'; + +export const getConnectorType = (): SubActionConnectorType => ({ + id: BEDROCK_CONNECTOR_ID, + name: BEDROCK_TITLE, + Service: BedrockConnector, + schema: { + config: ConfigSchema, + secrets: SecretsSchema, + }, + validators: [{ type: ValidatorType.CONFIG, validator: configValidator }], + supportedFeatureIds: [GeneralConnectorFeatureId], + minimumLicenseRequired: 'enterprise' as const, + renderParameterTemplates, +}); + +export const configValidator = (configObject: Config, validatorServices: ValidatorServices) => { + try { + assertURL(configObject.apiUrl); + urlAllowListValidator('apiUrl')(configObject, validatorServices); + + return configObject; + } catch (err) { + throw new Error( + i18n.translate('xpack.stackConnectors.bedrock.configurationErrorApiProvider', { + defaultMessage: 'Error configuring AWS Bedrock action: {err}', + values: { + err, + }, + }) + ); + } +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts new file mode 100644 index 00000000000000..bdbe7921155625 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderParameterTemplates } from './render'; +import Mustache from 'mustache'; + +const params = { + subAction: 'run', + subActionParams: { + body: '{"domain":"{{domain}}"}', + }, +}; + +const variables = { domain: 'm0zepcuuu2' }; + +describe('Bedrock - renderParameterTemplates', () => { + it('should not render body on test action', () => { + const testParams = { subAction: 'test', subActionParams: { body: 'test_json' } }; + const result = renderParameterTemplates(testParams, variables); + expect(result).toEqual(testParams); + }); + + it('should rendered body with variables', () => { + const result = renderParameterTemplates(params, variables); + + expect(result.subActionParams.body).toEqual( + JSON.stringify({ + ...variables, + }) + ); + }); + + it('should render error body', () => { + const errorMessage = 'test error'; + jest.spyOn(Mustache, 'render').mockImplementation(() => { + throw new Error(errorMessage); + }); + const result = renderParameterTemplates(params, variables); + expect(result.subActionParams.body).toEqual( + 'error rendering mustache template "{"domain":"{{domain}}"}": test error' + ); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts new file mode 100644 index 00000000000000..34dd90ff2a862c --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/render.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExecutorParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { renderMustacheString } from '@kbn/actions-plugin/server/lib/mustache_renderer'; +import { RenderParameterTemplates } from '@kbn/actions-plugin/server/types'; +import { SUB_ACTION } from '../../../common/bedrock/constants'; + +export const renderParameterTemplates: RenderParameterTemplates = ( + params, + variables +) => { + if (params?.subAction !== SUB_ACTION.RUN && params?.subAction !== SUB_ACTION.TEST) return params; + + return { + ...params, + subActionParams: { + ...params.subActionParams, + body: renderMustacheString(params.subActionParams.body as string, variables, 'json'), + }, + }; +}; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.test.ts index b13fa276beacbb..490f7f7cfc23f0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { initGenAiDashboard } from './create_dashboard'; -import { getGenAiDashboard } from './dashboard'; +import { initDashboard } from './create_dashboard'; +import { getDashboard } from './dashboard'; import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { Logger } from '@kbn/logging'; @@ -24,7 +24,7 @@ describe('createDashboard', () => { }); it('fetches the Gen Ai Dashboard saved object', async () => { const dashboardId = 'test-dashboard-id'; - const result = await initGenAiDashboard({ logger, savedObjectsClient, dashboardId }); + const result = await initDashboard({ logger, savedObjectsClient, dashboardId }); expect(result.success).toBe(true); expect(logger.error).not.toHaveBeenCalled(); expect(savedObjectsClient.get).toHaveBeenCalledWith('dashboard', dashboardId); @@ -46,12 +46,12 @@ describe('createDashboard', () => { }, }), }; - const result = await initGenAiDashboard({ logger, savedObjectsClient: soClient, dashboardId }); + const result = await initDashboard({ logger, savedObjectsClient: soClient, dashboardId }); expect(soClient.get).toHaveBeenCalledWith('dashboard', dashboardId); expect(soClient.create).toHaveBeenCalledWith( 'dashboard', - getGenAiDashboard(dashboardId).attributes, + getDashboard(dashboardId).attributes, { overwrite: true, id: dashboardId } ); expect(result.success).toBe(true); @@ -73,7 +73,7 @@ describe('createDashboard', () => { }), }; const dashboardId = 'test-dashboard-id'; - const result = await initGenAiDashboard({ logger, savedObjectsClient: soClient, dashboardId }); + const result = await initDashboard({ logger, savedObjectsClient: soClient, dashboardId }); expect(result.success).toBe(false); expect(result.error?.message).toBe('Internal Server Error: Error happened'); expect(result.error?.statusCode).toBe(500); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.ts index d1d09a2e50afd9..80c3bc8cc7f21b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/create_dashboard.ts @@ -8,14 +8,14 @@ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-ser import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; import { Logger } from '@kbn/logging'; -import { getGenAiDashboard } from './dashboard'; +import { getDashboard } from './dashboard'; export interface OutputError { message: string; statusCode: number; } -export const initGenAiDashboard = async ({ +export const initDashboard = async ({ logger, savedObjectsClient, dashboardId, @@ -50,7 +50,7 @@ export const initGenAiDashboard = async ({ try { await savedObjectsClient.create( 'dashboard', - getGenAiDashboard(dashboardId).attributes, + getDashboard(dashboardId).attributes, { overwrite: true, id: dashboardId, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/dashboard.ts index 46a4fa5145de5a..6470f088577b70 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/dashboard.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/dashboard.ts @@ -11,7 +11,7 @@ import { SavedObject } from '@kbn/core-saved-objects-common/src/server_types'; export const dashboardTitle = `Generative AI Token Usage`; -export const getGenAiDashboard = (dashboardId: string): SavedObject => { +export const getDashboard = (dashboardId: string): SavedObject => { const ids: Record = { genAiSavedObjectId: dashboardId, tokens: uuidv4(), diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.test.ts index 31f88dd0edb0be..650ff4dd5cdc3a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.test.ts @@ -14,18 +14,31 @@ import { } from '../../../common/gen_ai/constants'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { - GenAiRunActionResponseSchema, - GenAiStreamingResponseSchema, -} from '../../../common/gen_ai/schema'; -import { initGenAiDashboard } from './create_dashboard'; +import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/gen_ai/schema'; +import { initDashboard } from './create_dashboard'; jest.mock('./create_dashboard'); describe('GenAiConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; + const mockResponseString = 'Hello! How can I assist you today?'; + const mockResponse = { + headers: {}, + data: { + result: 'success', + choices: [ + { + message: { + role: 'assistant', + content: mockResponseString, + }, + finish_reason: 'stop', + index: 0, + }, + ], + }, + }; beforeEach(() => { - const mockResponse = { headers: {}, data: { result: 'success' } }; mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); @@ -68,14 +81,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), headers: { Authorization: 'Bearer 123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('overrides the default model with the default model specified in the body', async () => { @@ -85,14 +98,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...requestBody, stream: false }), headers: { Authorization: 'Bearer 123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters', async () => { @@ -101,14 +114,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), headers: { Authorization: 'Bearer 123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('overrides stream parameter if set in the body', async () => { @@ -131,7 +144,7 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...body, stream: false, @@ -141,7 +154,7 @@ describe('GenAiConnector', () => { 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('errors during API calls are properly handled', async () => { @@ -164,14 +177,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), headers: { Authorization: 'Bearer 123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters when stream = true', async () => { @@ -184,7 +197,7 @@ describe('GenAiConnector', () => { responseType: 'stream', url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiStreamingResponseSchema, + responseSchema: StreamingResponseSchema, data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), headers: { Authorization: 'Bearer 123', @@ -193,7 +206,7 @@ describe('GenAiConnector', () => { }); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, - result: 'success', + ...mockResponse.data, }); }); @@ -219,7 +232,7 @@ describe('GenAiConnector', () => { responseType: 'stream', url: 'https://api.openai.com/v1/chat/completions', method: 'post', - responseSchema: GenAiStreamingResponseSchema, + responseSchema: StreamingResponseSchema, data: JSON.stringify({ ...body, stream: true, @@ -231,7 +244,7 @@ describe('GenAiConnector', () => { }); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, - result: 'success', + ...mockResponse.data, }); }); @@ -244,6 +257,31 @@ describe('GenAiConnector', () => { ).rejects.toThrow('API Error'); }); }); + + describe('invokeAI', () => { + it('the API call is successful with correct parameters', async () => { + const response = await connector.invokeAI(sampleOpenAiBody); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith({ + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), + headers: { + Authorization: 'Bearer 123', + 'content-type': 'application/json', + }, + }); + expect(response).toEqual(mockResponseString); + }); + + it('errors during API calls are properly handled', async () => { + // @ts-ignore + connector.request = mockError; + + await expect(connector.invokeAI(sampleOpenAiBody)).rejects.toThrow('API Error'); + }); + }); }); describe('AzureAI', () => { @@ -282,14 +320,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), headers: { 'api-key': '123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('overrides stream parameter if set in the body', async () => { @@ -308,14 +346,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), headers: { 'api-key': '123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('errors during API calls are properly handled', async () => { @@ -338,14 +376,14 @@ describe('GenAiConnector', () => { expect(mockRequest).toHaveBeenCalledWith({ url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', method: 'post', - responseSchema: GenAiRunActionResponseSchema, + responseSchema: RunActionResponseSchema, data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), headers: { 'api-key': '123', 'content-type': 'application/json', }, }); - expect(response).toEqual({ result: 'success' }); + expect(response).toEqual(mockResponse.data); }); it('the AzureAI API call is successful with correct parameters when stream = true', async () => { @@ -358,7 +396,7 @@ describe('GenAiConnector', () => { responseType: 'stream', url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', method: 'post', - responseSchema: GenAiStreamingResponseSchema, + responseSchema: StreamingResponseSchema, data: JSON.stringify({ ...sampleAzureAiBody, stream: true }), headers: { 'api-key': '123', @@ -367,7 +405,7 @@ describe('GenAiConnector', () => { }); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, - result: 'success', + ...mockResponse.data, }); }); @@ -389,7 +427,7 @@ describe('GenAiConnector', () => { responseType: 'stream', url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', method: 'post', - responseSchema: GenAiStreamingResponseSchema, + responseSchema: StreamingResponseSchema, data: JSON.stringify({ ...body, stream: true, @@ -401,7 +439,7 @@ describe('GenAiConnector', () => { }); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, - result: 'success', + ...mockResponse.data, }); }); @@ -425,7 +463,7 @@ describe('GenAiConnector', () => { logger: loggingSystemMock.createLogger(), services: actionsMock.createServices(), }); - const mockGenAi = initGenAiDashboard as jest.Mock; + const mockGenAi = initDashboard as jest.Mock; beforeEach(() => { // @ts-ignore connector.esClient.transport.request = mockRequest; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.ts index c88d129db70713..4a0efbe11d4724 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/gen_ai.ts @@ -7,25 +7,28 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; -import { initGenAiDashboard } from './create_dashboard'; +import { initDashboard } from './create_dashboard'; import { - GenAiRunActionParamsSchema, - GenAiRunActionResponseSchema, - GenAiDashboardActionParamsSchema, - GenAiStreamActionParamsSchema, - GenAiStreamingResponseSchema, + RunActionParamsSchema, + RunActionResponseSchema, + DashboardActionParamsSchema, + StreamActionParamsSchema, + StreamingResponseSchema, + InvokeAIActionParamsSchema, } from '../../../common/gen_ai/schema'; import type { - GenAiConfig, - GenAiSecrets, - GenAiRunActionParams, - GenAiRunActionResponse, - GenAiStreamActionParams, + Config, + Secrets, + RunActionParams, + RunActionResponse, + StreamActionParams, } from '../../../common/gen_ai/types'; import { SUB_ACTION } from '../../../common/gen_ai/constants'; import { - GenAiDashboardActionParams, - GenAiDashboardActionResponse, + DashboardActionParams, + DashboardActionResponse, + InvokeAIActionParams, + InvokeAIActionResponse, } from '../../../common/gen_ai/types'; import { getAxiosOptions, @@ -34,12 +37,12 @@ import { sanitizeRequest, } from './lib/utils'; -export class GenAiConnector extends SubActionConnector { +export class GenAiConnector extends SubActionConnector { private url; private provider; private key; - constructor(params: ServiceParams) { + constructor(params: ServiceParams) { super(params); this.url = this.config.apiUrl; @@ -53,25 +56,31 @@ export class GenAiConnector extends SubActionConnector { + /** + * responsible for making a POST request to the external API endpoint and returning the response data + * @param body The stringified request body to be sent in the POST request. + */ + public async runApi({ body }: RunActionParams): Promise { const sanitizedBody = sanitizeRequest( this.provider, this.url, @@ -98,17 +110,22 @@ export class GenAiConnector extends SubActionConnector { + /** + * responsible for making a POST request to a specified URL with a given request body. + * The method can handle both regular API requests and streaming requests based on the stream parameter. + * It uses helper functions getRequestWithStreamOption and getAxiosOptions to prepare the request body and headers respectively. + * The response is then processed based on whether it is a streaming response or a regular response. + * @param body request body for the API request + * @param stream flag indicating whether it is a streaming request or not + */ + public async streamApi({ body, stream }: StreamActionParams): Promise { const executeBody = getRequestWithStreamOption( this.provider, this.url, @@ -121,16 +138,21 @@ export class GenAiConnector extends SubActionConnector { + }: DashboardActionParams): Promise { const privilege = (await this.esClient.transport.request({ path: '/_security/user/_has_privileges', method: 'POST', @@ -149,7 +171,7 @@ export class GenAiConnector extends SubActionConnector { + const res = await this.runApi({ body: JSON.stringify(body) }); + + if (res.choices && res.choices.length > 0 && res.choices[0].message?.content) { + const result = res.choices[0].message.content.trim(); + return result; + } + + // TO DO: Pass actual error + // tracked here https://github.com/elastic/security-team/issues/7373 + return 'An error occurred sending your message. If the problem persists, please test the connector configuration.'; + } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.test.ts index 75611b610dbeef..5ed6aaf070b88b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.test.ts @@ -9,7 +9,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import axios from 'axios'; import { configValidator, getConnectorType } from '.'; -import { GenAiConfig, GenAiSecrets } from '../../../common/gen_ai/types'; +import { Config, Secrets } from '../../../common/gen_ai/types'; import { SubActionConnectorType } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { DEFAULT_OPENAI_MODEL, OpenAiProviderType } from '../../../common/gen_ai/constants'; @@ -27,7 +27,7 @@ axios.create = jest.fn(() => axios); axios.create = jest.fn(() => axios); -let connectorType: SubActionConnectorType; +let connectorType: SubActionConnectorType; let configurationUtilities: jest.Mocked; describe('Generative AI Connector', () => { @@ -37,11 +37,11 @@ describe('Generative AI Connector', () => { }); test('exposes the connector as `Generative AI` with id `.gen-ai`', () => { expect(connectorType.id).toEqual('.gen-ai'); - expect(connectorType.name).toEqual('Generative AI'); + expect(connectorType.name).toEqual('OpenAI'); }); describe('config validation', () => { test('config validation passes when only required fields are provided', () => { - const config: GenAiConfig = { + const config: Config = { apiUrl: 'https://api.openai.com/v1/chat/completions', apiProvider: OpenAiProviderType.OpenAi, defaultModel: DEFAULT_OPENAI_MODEL, @@ -51,7 +51,7 @@ describe('Generative AI Connector', () => { }); test('config validation failed when a url is invalid', () => { - const config: GenAiConfig = { + const config: Config = { apiUrl: 'example.com/do-something', apiProvider: OpenAiProviderType.OpenAi, defaultModel: DEFAULT_OPENAI_MODEL, @@ -64,7 +64,7 @@ describe('Generative AI Connector', () => { }); test('config validation failed when the OpenAI API provider is empty', () => { - const config: GenAiConfig = { + const config: Config = { apiUrl: 'https://api.openai.com/v1/chat/completions', apiProvider: '' as OpenAiProviderType, defaultModel: DEFAULT_OPENAI_MODEL, @@ -77,7 +77,7 @@ describe('Generative AI Connector', () => { }); test('config validation failed when the OpenAI API provider is invalid', () => { - const config: GenAiConfig = { + const config: Config = { apiUrl: 'https://api.openai.com/v1/chat/completions', apiProvider: 'bad-one' as OpenAiProviderType, defaultModel: DEFAULT_OPENAI_MODEL, @@ -97,7 +97,7 @@ describe('Generative AI Connector', () => { }, }; - const config: GenAiConfig = { + const config: Config = { apiUrl: 'http://mylisteningserver.com:9200/endpoint', apiProvider: OpenAiProviderType.OpenAi, defaultModel: DEFAULT_OPENAI_MODEL, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.ts index f845215ddba48f..cc43a05fd346dd 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gen_ai/index.ts @@ -16,21 +16,21 @@ import { ValidatorServices } from '@kbn/actions-plugin/server/types'; import { assertURL } from '@kbn/actions-plugin/server/sub_action_framework/helpers/validators'; import { GEN_AI_CONNECTOR_ID, - GEN_AI_TITLE, + OPEN_AI_TITLE, OpenAiProviderType, } from '../../../common/gen_ai/constants'; -import { GenAiConfigSchema, GenAiSecretsSchema } from '../../../common/gen_ai/schema'; -import { GenAiConfig, GenAiSecrets } from '../../../common/gen_ai/types'; +import { ConfigSchema, SecretsSchema } from '../../../common/gen_ai/schema'; +import { Config, Secrets } from '../../../common/gen_ai/types'; import { GenAiConnector } from './gen_ai'; import { renderParameterTemplates } from './render'; -export const getConnectorType = (): SubActionConnectorType => ({ +export const getConnectorType = (): SubActionConnectorType => ({ id: GEN_AI_CONNECTOR_ID, - name: GEN_AI_TITLE, + name: OPEN_AI_TITLE, Service: GenAiConnector, schema: { - config: GenAiConfigSchema, - secrets: GenAiSecretsSchema, + config: ConfigSchema, + secrets: SecretsSchema, }, validators: [{ type: ValidatorType.CONFIG, validator: configValidator }], supportedFeatureIds: [GeneralConnectorFeatureId], @@ -38,10 +38,7 @@ export const getConnectorType = (): SubActionConnectorType { +export const configValidator = (configObject: Config, validatorServices: ValidatorServices) => { try { assertURL(configObject.apiUrl); urlAllowListValidator('apiUrl')(configObject, validatorServices); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/index.ts index a6c5d6ec2f9054..743f2664ed0b52 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/index.ts @@ -18,6 +18,7 @@ import { getActionType as getTorqConnectorType } from './torq'; import { getConnectorType as getEmailConnectorType } from './email'; import { getConnectorType as getIndexConnectorType } from './es_index'; import { getConnectorType as getGenerativeAiConnectorType } from './gen_ai'; +import { getConnectorType as getBedrockConnectorType } from './bedrock'; import { getConnectorType as getPagerDutyConnectorType } from './pagerduty'; import { getConnectorType as getSwimlaneConnectorType } from './swimlane'; import { getConnectorType as getServerLogConnectorType } from './server_log'; @@ -101,5 +102,6 @@ export function registerConnectorTypes({ actions.registerSubActionConnectorType(getOpsgenieConnectorType()); actions.registerSubActionConnectorType(getTinesConnectorType()); actions.registerSubActionConnectorType(getGenerativeAiConnectorType()); + actions.registerSubActionConnectorType(getBedrockConnectorType()); actions.registerSubActionConnectorType(getD3SecurityConnectorType()); } diff --git a/x-pack/plugins/stack_connectors/server/plugin.test.ts b/x-pack/plugins/stack_connectors/server/plugin.test.ts index 87d9ca97edb0a0..c728ee92cea407 100644 --- a/x-pack/plugins/stack_connectors/server/plugin.test.ts +++ b/x-pack/plugins/stack_connectors/server/plugin.test.ts @@ -138,7 +138,7 @@ describe('Stack Connectors Plugin', () => { name: 'Torq', }) ); - expect(actionsSetup.registerSubActionConnectorType).toHaveBeenCalledTimes(4); + expect(actionsSetup.registerSubActionConnectorType).toHaveBeenCalledTimes(5); expect(actionsSetup.registerSubActionConnectorType).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -157,11 +157,18 @@ describe('Stack Connectors Plugin', () => { 3, expect.objectContaining({ id: '.gen-ai', - name: 'Generative AI', + name: 'OpenAI', }) ); expect(actionsSetup.registerSubActionConnectorType).toHaveBeenNthCalledWith( 4, + expect.objectContaining({ + id: '.bedrock', + name: 'AWS Bedrock', + }) + ); + expect(actionsSetup.registerSubActionConnectorType).toHaveBeenNthCalledWith( + 5, expect.objectContaining({ id: '.d3security', name: 'D3 Security', diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index 823ef92ea32ca8..7fdd7668135a49 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -33,6 +33,7 @@ interface CreateTestConfigOptions { // test.not-enabled is specifically not enabled const enabledActionTypes = [ + '.bedrock', '.cases-webhook', '.email', '.index', diff --git a/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts new file mode 100644 index 00000000000000..bfa8c5cb0736fd --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/bedrock_simulation.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import http from 'http'; + +import { ProxyArgs, Simulator } from './simulator'; + +export class BedrockSimulator extends Simulator { + private readonly returnError: boolean; + + constructor({ returnError = false, proxy }: { returnError?: boolean; proxy?: ProxyArgs }) { + super(proxy); + + this.returnError = returnError; + } + + public async handler( + request: http.IncomingMessage, + response: http.ServerResponse, + data: Record + ) { + if (this.returnError) { + return BedrockSimulator.sendErrorResponse(response); + } + + return BedrockSimulator.sendResponse(response); + } + + private static sendResponse(response: http.ServerResponse) { + response.statusCode = 202; + response.setHeader('Content-Type', 'application/json'); + response.end(JSON.stringify(bedrockSuccessResponse, null, 4)); + } + + private static sendErrorResponse(response: http.ServerResponse) { + response.statusCode = 422; + response.setHeader('Content-Type', 'application/json;charset=UTF-8'); + response.end(JSON.stringify(bedrockFailedResponse, null, 4)); + } +} + +export const bedrockSuccessResponse = { + stop_reason: 'max_tokens', + completion: 'Hello there! How may I assist you today?', +}; + +export const bedrockFailedResponse = { + message: + 'Malformed input request: extraneous key [ooooo] is not permitted, please reformat your input and try again.', +}; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts new file mode 100644 index 00000000000000..18260ac4244d85 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -0,0 +1,450 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + BedrockSimulator, + bedrockSuccessResponse, +} from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; +import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; + +const connectorTypeId = '.bedrock'; +const name = 'A bedrock action'; +const secrets = { + accessKey: 'bedrockAccessKey', + secret: 'bedrockSecret', +}; + +const defaultConfig = { + defaultModel: 'anthropic.claude-v2', +}; + +// eslint-disable-next-line import/no-default-export +export default function bedrockTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const objectRemover = new ObjectRemover(supertest); + const configService = getService('config'); + const createConnector = async (apiUrl: string, spaceId?: string) => { + const result = await supertest + .post(`${getUrlPrefix(spaceId ?? 'default')}/api/actions/connector`) + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config: { ...defaultConfig, apiUrl }, + secrets, + }) + .expect(200); + + const { body } = result; + + objectRemover.add(spaceId ?? 'default', body.id, 'connector', 'actions'); + + return body.id; + }; + + describe('Bedrock', () => { + after(() => { + objectRemover.removeAll(); + }); + describe('action creation', () => { + const simulator = new BedrockSimulator({ + returnError: false, + proxy: { + config: configService.get('kbnTestServer.serverArgs'), + }, + }); + const config = { ...defaultConfig, apiUrl: '' }; + + before(async () => { + config.apiUrl = await simulator.start(); + }); + + after(() => { + simulator.close(); + }); + + it('should return 200 when creating the connector', async () => { + const { body: createdAction } = await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config, + secrets, + }) + .expect(200); + expect(createdAction).to.eql({ + id: createdAction.id, + is_preconfigured: false, + is_system_action: false, + is_deprecated: false, + name, + connector_type_id: connectorTypeId, + is_missing_secrets: false, + config, + }); + }); + + it('Falls back to default model when connector is created without the model', async () => { + const { defaultModel: _, ...rest } = config; + const { body: createdAction } = await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config: rest, + secrets, + }) + .expect(200); + + expect(createdAction).to.eql({ + id: createdAction.id, + is_preconfigured: false, + is_system_action: false, + is_deprecated: false, + name, + connector_type_id: connectorTypeId, + is_missing_secrets: false, + config, + }); + }); + + it('should return 400 Bad Request when creating the connector without the apiUrl', async () => { + const { apiUrl: _, ...rest } = config; + await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config: rest, + secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should return 400 Bad Request when creating the connector with a apiUrl that is not allowed', async () => { + await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config: { + ...defaultConfig, + apiUrl: 'http://bedrock.mynonexistent.com', + }, + secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: Error configuring AWS Bedrock action: Error: error validating url: target url "http://bedrock.mynonexistent.com" is not added to the Kibana config xpack.actions.allowedHosts', + }); + }); + }); + + it('should return 400 Bad Request when creating the connector without secrets', async () => { + await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: [accessKey]: expected value of type [string] but got [undefined]', + }); + }); + }); + it('should return 400 Bad Request when creating the connector without accessKey secret', async () => { + await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config, + secrets: { + secret: 'secret', + }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: [accessKey]: expected value of type [string] but got [undefined]', + }); + }); + }); + it('should return 400 Bad Request when creating the connector without secret secret', async () => { + await supertest + .post('/api/actions/connector') + .set('kbn-xsrf', 'foo') + .send({ + name, + connector_type_id: connectorTypeId, + config, + secrets: { + accessKey: 'accessKey', + }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: [secret]: expected value of type [string] but got [undefined]', + }); + }); + }); + }); + + describe('executor', () => { + describe('validation', () => { + const simulator = new BedrockSimulator({ + proxy: { + config: configService.get('kbnTestServer.serverArgs'), + }, + }); + let bedrockActionId: string; + + before(async () => { + const apiUrl = await simulator.start(); + bedrockActionId = await createConnector(apiUrl); + }); + + after(() => { + simulator.close(); + }); + + it('should fail when the params is empty', async () => { + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: {}, + }); + expect(200); + + expect(body).to.eql({ + status: 'error', + connector_id: bedrockActionId, + message: + 'error validating action params: [subAction]: expected value of type [string] but got [undefined]', + retry: false, + }); + }); + + it('should fail when the subAction is invalid', async () => { + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'invalidAction' }, + }) + .expect(200); + + expect(body).to.eql({ + connector_id: bedrockActionId, + status: 'error', + retry: true, + message: 'an error occurred while running the action', + service_message: `Sub action "invalidAction" is not registered. Connector id: ${bedrockActionId}. Connector name: AWS Bedrock. Connector type: .bedrock`, + }); + }); + }); + + describe('execution', () => { + describe('successful response simulator', () => { + const simulator = new BedrockSimulator({ + proxy: { + config: configService.get('kbnTestServer.serverArgs'), + }, + }); + let apiUrl: string; + let bedrockActionId: string; + + before(async () => { + apiUrl = await simulator.start(); + bedrockActionId = await createConnector(apiUrl); + }); + + after(() => { + simulator.close(); + }); + + it('should send a stringified JSON object', async () => { + const DEFAULT_BODY = { + prompt: `Hello world!`, + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'], + }; + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'test', + subActionParams: { + body: JSON.stringify(DEFAULT_BODY), + }, + }, + }) + .expect(200); + + expect(simulator.requestData).to.eql(DEFAULT_BODY); + expect(simulator.requestUrl).to.eql( + `${apiUrl}/model/${defaultConfig.defaultModel}/invoke` + ); + expect(body).to.eql({ + status: 'ok', + connector_id: bedrockActionId, + data: bedrockSuccessResponse, + }); + }); + + it('should overwrite the model when a model argument is provided', async () => { + const DEFAULT_BODY = { + prompt: `Hello world!`, + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'], + }; + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'test', + subActionParams: { + body: JSON.stringify(DEFAULT_BODY), + model: 'some-other-model', + }, + }, + }) + .expect(200); + + expect(simulator.requestData).to.eql(DEFAULT_BODY); + expect(simulator.requestUrl).to.eql(`${apiUrl}/model/some-other-model/invoke`); + expect(body).to.eql({ + status: 'ok', + connector_id: bedrockActionId, + data: bedrockSuccessResponse, + }); + }); + + it('should invoke AI with assistant AI body argument formatted to bedrock expectations', async () => { + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + subAction: 'invokeAI', + subActionParams: { + messages: [ + { + role: 'user', + content: 'Hello world', + }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, + ], + }, + }, + }) + .expect(200); + + expect(simulator.requestData).to.eql({ + prompt: + '\n\nHuman:Hello world\n\nHuman:Be a good chatbot\n\nAssistant:Hi, I am a good chatbot\n\nHuman:What is 2+2? \n\nAssistant:', + max_tokens_to_sample: 300, + stop_sequences: ['\n\nHuman:'], + }); + expect(body).to.eql({ + status: 'ok', + connector_id: bedrockActionId, + data: bedrockSuccessResponse.completion, + }); + }); + }); + }); + + describe('error response simulator', () => { + const simulator = new BedrockSimulator({ + returnError: true, + proxy: { + config: configService.get('kbnTestServer.serverArgs'), + }, + }); + + let bedrockActionId: string; + + before(async () => { + const apiUrl = await simulator.start(); + bedrockActionId = await createConnector(apiUrl); + }); + + after(() => { + simulator.close(); + }); + + it('should return a failure when error happens', async () => { + const { body } = await supertest + .post(`/api/actions/connector/${bedrockActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: {}, + }) + .expect(200); + + expect(body).to.eql({ + status: 'error', + connector_id: bedrockActionId, + message: + 'error validating action params: [subAction]: expected value of type [string] but got [undefined]', + retry: false, + }); + }); + }); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/gen_ai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/gen_ai.ts index b52d9c14cc3a73..5cfe992171dacb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/gen_ai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/gen_ai.ts @@ -265,7 +265,7 @@ export default function genAiTest({ getService }: FtrProviderContext) { status: 'error', retry: true, message: 'an error occurred while running the action', - service_message: `Sub action "invalidAction" is not registered. Connector id: ${genAiActionId}. Connector name: Generative AI. Connector type: .gen-ai`, + service_message: `Sub action "invalidAction" is not registered. Connector id: ${genAiActionId}. Connector name: OpenAI. Connector type: .gen-ai`, }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/index.ts index 6b57d75b268356..fd667f8f1025a9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/index.ts @@ -41,6 +41,7 @@ export default function connectorsTests({ loadTestFile, getService }: FtrProvide loadTestFile(require.resolve('./connector_types/torq')); loadTestFile(require.resolve('./connector_types/gen_ai')); loadTestFile(require.resolve('./connector_types/d3security')); + loadTestFile(require.resolve('./connector_types/bedrock')); loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); loadTestFile(require.resolve('./execute')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/check_registered_connector_types.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/check_registered_connector_types.ts index 257d774c160ddd..13fcc069a4df31 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/check_registered_connector_types.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/check_registered_connector_types.ts @@ -49,6 +49,7 @@ export default function createRegisteredConnectorTypeTests({ getService }: FtrPr '.torq', '.opsgenie', '.gen-ai', + '.bedrock', ].sort() ); }); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index a5f039eaed5f28..5f4657341da45c 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -50,6 +50,7 @@ export default function ({ getService }: FtrProviderContext) { 'ML:saved-objects-sync', 'Synthetics:Clean-Up-Package-Policies', 'UPTIME:SyntheticsService:Sync-Saved-Monitor-Objects', + 'actions:.bedrock', 'actions:.cases-webhook', 'actions:.d3security', 'actions:.email', diff --git a/yarn.lock b/yarn.lock index 9dc5ced6ac193f..861e3d293a17ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8544,6 +8544,13 @@ resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.15.tgz#26d4768fdda0e466f18d6c9918ca28cc89a4e1fe" integrity sha512-PAmPfzvFA31mRoqZyTVsgJMsvbynR429UTTxhmfsUCrWGh3/fxOrzqBtaTPJsn4UtzTv4Vb0+/O7CARWb69N4g== +"@types/aws4@^1.5.0": + version "1.11.3" + resolved "https://registry.yarnpkg.com/@types/aws4/-/aws4-1.11.3.tgz#a7856fe4e30a7b6411335a73d5440e8b91afc662" + integrity sha512-Ka2xKf04xZUH0N7wIYpqcNdavgfPQnaJ1T6GieZs1ydo21vao93aCbHyrA6uKXnaTXzvBcMJkgMsBfT9XvypFQ== + dependencies: + "@types/node" "*" + "@types/babel__core@*", "@types/babel__core@^7.1.14": version "7.1.20" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.20.tgz#e168cdd612c92a2d335029ed62ac94c95b362359" @@ -11435,6 +11442,11 @@ aws-sign2@~0.7.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= +aws4@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== + aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" From 8838ac1d180231e537a9039e432f8582140fec59 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 27 Sep 2023 18:47:11 -0400 Subject: [PATCH 18/22] skip failing test suite (#167405) --- test/functional/apps/discover/group1/_shared_links.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/discover/group1/_shared_links.ts b/test/functional/apps/discover/group1/_shared_links.ts index 30626d9d42576d..6ea6a9dac19a95 100644 --- a/test/functional/apps/discover/group1/_shared_links.ts +++ b/test/functional/apps/discover/group1/_shared_links.ts @@ -22,7 +22,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const toasts = getService('toasts'); const deployment = getService('deployment'); - describe('shared links', function describeIndexTests() { + // Failing: See https://github.com/elastic/kibana/issues/167405 + describe.skip('shared links', function describeIndexTests() { let baseUrl: string; async function setup({ storeStateInSessionStorage }: { storeStateInSessionStorage: boolean }) { From 272219ca49956956a17b465d48838c763ac728a4 Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 27 Sep 2023 18:00:28 -0500 Subject: [PATCH 19/22] [fleet] Fix key path (#167448) In https://github.com/elastic/kibana/pull/167148 the filename was updated. This updates the file read path in the fleet plugin. Fixes `proc [kibana] [2023-09-27T18:12:07.561+00:00][WARN ][plugins.fleet] Unable to retrieve GPG key from '/var/lib/buildkite-agent/builds/kb-n2-4-spot-e622c074d3147d71/elastic/kibana-on-merge/kibana-build-xpack/node_modules/@kbn/fleet-plugin/target/keys/GPG-KEY-elasticsearch': ENOENT` --- x-pack/plugins/fleet/server/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index cbf38a20247335..b68684460bf810 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -27,7 +27,7 @@ import { import { BULK_CREATE_MAX_ARTIFACTS_BYTES } from './services/artifacts/artifacts'; const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages'); -const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch'); +const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch.sha1'); const REGISTRY_SPEC_MAX_VERSION = '3.0'; From 3e1865513d3e59cb93c073a6c6663aabf65cc5a6 Mon Sep 17 00:00:00 2001 From: Davis McPhee Date: Wed, 27 Sep 2023 21:52:25 -0300 Subject: [PATCH 20/22] [Discover] Add resize support to the Discover field list sidebar (#167066) ## Summary This PR adds resize support to the Discover field list sidebar, which is persisted to a user's local storage similar to the resizable chart height. Additionally it migrates the resizable layout code from Unified Histogram to a new package called `kbn-resizable-layout` so it can be shared between Discover and Unified Histogram, as well as act as a new platform component that other teams can consume to create their own resizable layouts. ![resize](https://github.com/elastic/kibana/assets/25592674/71b9a0ae-1795-43c8-acb0-e75fe46e2a8a) Resolves #9531. ### Checklist - [ ] ~Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)~ - [ ] ~[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] 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)~ - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 2 + .../resizable_layout_examples/kibana.jsonc | 11 + .../public/application.tsx | 161 ++++++++++++ .../resizable_layout_examples/public/index.ts | 13 + .../public/plugin.tsx | 44 ++++ .../public/resizable_layout_examples.png | Bin 0 -> 30405 bytes .../resizable_layout_examples/tsconfig.json | 15 ++ package.json | 2 + packages/kbn-resizable-layout/README.md | 85 ++++++ packages/kbn-resizable-layout/index.ts | 14 + .../kbn-resizable-layout/jest.config.js | 6 +- packages/kbn-resizable-layout/kibana.jsonc | 6 + packages/kbn-resizable-layout/package.json | 6 + .../src/panels_resizable.test.tsx | 246 ++++++++++++++++++ .../src/panels_resizable.tsx | 228 ++++++++++++++++ .../src/panels_static.test.tsx | 71 +++++ .../src/panels_static.tsx | 28 +- .../src/resizable_layout.test.tsx | 106 ++++++++ .../src/resizable_layout.tsx | 130 +++++++++ .../kbn-resizable-layout/src/utils.test.ts | 40 +++ packages/kbn-resizable-layout/src/utils.ts | 22 ++ packages/kbn-resizable-layout/tsconfig.json | 11 + packages/kbn-resizable-layout/types.ts | 33 +++ .../field_list_sidebar.scss | 9 +- .../field_list_sidebar.tsx | 7 + .../field_list_sidebar_container.tsx | 10 +- .../layout/discover_histogram_layout.test.tsx | 2 +- .../layout/discover_histogram_layout.tsx | 8 +- .../components/layout/discover_layout.scss | 14 + .../layout/discover_layout.test.tsx | 5 + .../components/layout/discover_layout.tsx | 173 +++++++----- .../layout/discover_resizable_layout.test.tsx | 169 ++++++++++++ .../layout/discover_resizable_layout.tsx | 80 ++++++ .../discover_sidebar_responsive.test.tsx | 80 +++--- .../sidebar/discover_sidebar_responsive.tsx | 10 +- src/plugins/discover/tsconfig.json | 3 +- .../public/container/container.test.tsx | 4 +- .../public/container/container.tsx | 2 +- .../public/layout/layout.test.tsx | 56 ++-- .../public/layout/layout.tsx | 55 ++-- .../public/panels/panels.test.tsx | 95 ------- .../public/panels/panels.tsx | 59 ----- .../public/panels/panels_fixed.test.tsx | 44 ---- .../public/panels/panels_resizable.test.tsx | 197 -------------- .../public/panels/panels_resizable.tsx | 197 -------------- src/plugins/unified_histogram/tsconfig.json | 1 + .../apps/discover/group1/_discover.ts | 31 ++- .../management/data_views/_scripted_fields.ts | 4 - .../_scripted_fields_classic_table.ts | 4 - tsconfig.base.json | 4 + yarn.lock | 8 + 51 files changed, 1822 insertions(+), 789 deletions(-) create mode 100644 examples/resizable_layout_examples/kibana.jsonc create mode 100644 examples/resizable_layout_examples/public/application.tsx create mode 100644 examples/resizable_layout_examples/public/index.ts create mode 100644 examples/resizable_layout_examples/public/plugin.tsx create mode 100644 examples/resizable_layout_examples/public/resizable_layout_examples.png create mode 100644 examples/resizable_layout_examples/tsconfig.json create mode 100644 packages/kbn-resizable-layout/README.md create mode 100644 packages/kbn-resizable-layout/index.ts rename src/plugins/unified_histogram/public/panels/index.ts => packages/kbn-resizable-layout/jest.config.js (74%) create mode 100644 packages/kbn-resizable-layout/kibana.jsonc create mode 100644 packages/kbn-resizable-layout/package.json create mode 100644 packages/kbn-resizable-layout/src/panels_resizable.test.tsx create mode 100644 packages/kbn-resizable-layout/src/panels_resizable.tsx create mode 100644 packages/kbn-resizable-layout/src/panels_static.test.tsx rename src/plugins/unified_histogram/public/panels/panels_fixed.tsx => packages/kbn-resizable-layout/src/panels_static.tsx (68%) create mode 100644 packages/kbn-resizable-layout/src/resizable_layout.test.tsx create mode 100644 packages/kbn-resizable-layout/src/resizable_layout.tsx create mode 100644 packages/kbn-resizable-layout/src/utils.test.ts create mode 100644 packages/kbn-resizable-layout/src/utils.ts create mode 100644 packages/kbn-resizable-layout/tsconfig.json create mode 100644 packages/kbn-resizable-layout/types.ts create mode 100644 src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.test.tsx create mode 100644 src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.tsx delete mode 100644 src/plugins/unified_histogram/public/panels/panels.test.tsx delete mode 100644 src/plugins/unified_histogram/public/panels/panels.tsx delete mode 100644 src/plugins/unified_histogram/public/panels/panels_fixed.test.tsx delete mode 100644 src/plugins/unified_histogram/public/panels/panels_resizable.test.tsx delete mode 100644 src/plugins/unified_histogram/public/panels/panels_resizable.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index af6ce61ca4b588..be401c26dc0d20 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -581,6 +581,8 @@ packages/kbn-repo-source-classifier-cli @elastic/kibana-operations packages/kbn-reporting/common @elastic/appex-sharedux x-pack/examples/reporting_example @elastic/appex-sharedux x-pack/plugins/reporting @elastic/appex-sharedux +packages/kbn-resizable-layout @elastic/kibana-data-discovery +examples/resizable_layout_examples @elastic/kibana-data-discovery x-pack/test/plugin_functional/plugins/resolver_test @elastic/security-solution examples/response_stream @elastic/ml-ui packages/kbn-rison @elastic/kibana-operations diff --git a/examples/resizable_layout_examples/kibana.jsonc b/examples/resizable_layout_examples/kibana.jsonc new file mode 100644 index 00000000000000..6c6e3e6360cb43 --- /dev/null +++ b/examples/resizable_layout_examples/kibana.jsonc @@ -0,0 +1,11 @@ +{ + "type": "plugin", + "id": "@kbn/resizable-layout-examples-plugin", + "owner": "@elastic/kibana-data-discovery", + "plugin": { + "id": "resizableLayoutExamples", + "server": false, + "browser": true, + "requiredPlugins": ["developerExamples"] + } +} diff --git a/examples/resizable_layout_examples/public/application.tsx b/examples/resizable_layout_examples/public/application.tsx new file mode 100644 index 00000000000000..350530be022fef --- /dev/null +++ b/examples/resizable_layout_examples/public/application.tsx @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { CoreThemeProvider } from '@kbn/core-theme-browser-internal'; +import type { AppMountParameters } from '@kbn/core/public'; +import { I18nProvider } from '@kbn/i18n-react'; +import React, { ReactNode, useState } from 'react'; +import ReactDOM from 'react-dom'; +import { useIsWithinBreakpoints } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { + ResizableLayout, + ResizableLayoutDirection, + ResizableLayoutMode, +} from '@kbn/resizable-layout'; +import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; + +const ResizableSection = ({ + direction, + initialFixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + fixedPanelColor, + flexPanelColor, + fixedPanelContent, + flexPanelContent, +}: { + direction: ResizableLayoutDirection; + initialFixedPanelSize: number; + minFixedPanelSize: number; + minFlexPanelSize: number; + fixedPanelColor: string; + flexPanelColor: string; + fixedPanelContent: ReactNode; + flexPanelContent: ReactNode; +}) => { + const [fixedPanelSize, setFixedPanelSize] = useState(initialFixedPanelSize); + const [container, setContainer] = useState(null); + const [fixedPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + const [flexPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + + const isMobile = useIsWithinBreakpoints(['xs', 's']); + const layoutMode = isMobile ? ResizableLayoutMode.Static : ResizableLayoutMode.Resizable; + const layoutDirection = isMobile ? ResizableLayoutDirection.Vertical : direction; + + const fullWidthAndHeightCss = css` + position: relative; + width: 100%; + height: 100%; + `; + const panelBaseCss = css` + ${fullWidthAndHeightCss} + padding: 20px; + font-size: 20px; + display: flex; + align-items: center; + justify-content: center; + `; + const fixedPanelCss = css` + ${panelBaseCss} + background-color: ${fixedPanelColor}; + `; + const flexPanelCss = css` + ${panelBaseCss} + background-color: ${flexPanelColor}; + `; + + return ( +
+ +
{fixedPanelContent}
+
+ +
{flexPanelContent}
+
+ } + flexPanel={} + onFixedPanelSizeChange={setFixedPanelSize} + /> +
+ ); +}; + +export const renderApp = ({ element, theme$ }: AppMountParameters) => { + ReactDOM.render( + + +
+ + } + flexPanelContent={ + + } + /> + } + /> +
+
+
, + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/examples/resizable_layout_examples/public/index.ts b/examples/resizable_layout_examples/public/index.ts new file mode 100644 index 00000000000000..26123cbb596129 --- /dev/null +++ b/examples/resizable_layout_examples/public/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ResizableLayoutExamplesPlugin } from './plugin'; + +export function plugin() { + return new ResizableLayoutExamplesPlugin(); +} diff --git a/examples/resizable_layout_examples/public/plugin.tsx b/examples/resizable_layout_examples/public/plugin.tsx new file mode 100644 index 00000000000000..b1f3bcbb2e2681 --- /dev/null +++ b/examples/resizable_layout_examples/public/plugin.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AppMountParameters, AppNavLinkStatus, CoreSetup, Plugin } from '@kbn/core/public'; +import type { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; +import image from './resizable_layout_examples.png'; + +export interface ResizableLayoutExamplesSetupPlugins { + developerExamples: DeveloperExamplesSetup; +} + +const PLUGIN_ID = 'resizableLayoutExamples'; +const PLUGIN_NAME = 'Resizable Layout Examples'; + +export class ResizableLayoutExamplesPlugin implements Plugin { + setup(core: CoreSetup, plugins: ResizableLayoutExamplesSetupPlugins) { + core.application.register({ + id: PLUGIN_ID, + title: PLUGIN_NAME, + navLinkStatus: AppNavLinkStatus.hidden, + mount: async (params: AppMountParameters) => { + // Load application bundle + const { renderApp } = await import('./application'); + // Render the application + return renderApp(params); + }, + }); + + plugins.developerExamples.register({ + appId: PLUGIN_ID, + title: PLUGIN_NAME, + description: + 'A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts.', + image, + }); + } + + start() {} +} diff --git a/examples/resizable_layout_examples/public/resizable_layout_examples.png b/examples/resizable_layout_examples/public/resizable_layout_examples.png new file mode 100644 index 0000000000000000000000000000000000000000..b89eca91d838e7a41ba2f0fe29935f76e7dc9de0 GIT binary patch literal 30405 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 b-;$I&Q_$Xyac6G7d+DmdHGRxw*N6WPKvZ*O literal 0 HcmV?d00001 diff --git a/examples/resizable_layout_examples/tsconfig.json b/examples/resizable_layout_examples/tsconfig.json new file mode 100644 index 00000000000000..e998e2c117f450 --- /dev/null +++ b/examples/resizable_layout_examples/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": ["common/**/*", "public/**/*", "server/**/*", "../../typings/**/*"], + "kbn_references": [ + "@kbn/resizable-layout", + "@kbn/core-theme-browser-internal", + "@kbn/core", + "@kbn/i18n-react", + "@kbn/developer-examples-plugin", + ], + "exclude": ["target/**/*"] +} diff --git a/package.json b/package.json index 6f6f4352380e1b..3b7f8c030fc8f0 100644 --- a/package.json +++ b/package.json @@ -588,6 +588,8 @@ "@kbn/reporting-common": "link:packages/kbn-reporting/common", "@kbn/reporting-example-plugin": "link:x-pack/examples/reporting_example", "@kbn/reporting-plugin": "link:x-pack/plugins/reporting", + "@kbn/resizable-layout": "link:packages/kbn-resizable-layout", + "@kbn/resizable-layout-examples-plugin": "link:examples/resizable_layout_examples", "@kbn/resolver-test-plugin": "link:x-pack/test/plugin_functional/plugins/resolver_test", "@kbn/response-stream-plugin": "link:examples/response_stream", "@kbn/rison": "link:packages/kbn-rison", diff --git a/packages/kbn-resizable-layout/README.md b/packages/kbn-resizable-layout/README.md new file mode 100644 index 00000000000000..41e94071325fe8 --- /dev/null +++ b/packages/kbn-resizable-layout/README.md @@ -0,0 +1,85 @@ +# @kbn/resizable-layout + +A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. + +## Example + +> [!NOTE] +> For advanced usage see [the example plugin](/examples/resizable_layout_examples/public/application.tsx). + +```tsx +import { useIsWithinBreakpoints } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { + ResizableLayout, + ResizableLayoutDirection, + ResizableLayoutMode, +} from '@kbn/resizable-layout'; +import React, { useRef, useState } from 'react'; +// Using react-reverse-portal is recommended for complex/heavy layouts to prevent +// re-mounting panel components when the layout switches from resizable to static +import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; + +export const ResizablePage = () => { + const [fixedPanelSize, setFixedPanelSize] = useState(500); + const [container, setContainer] = useState(null); + const [fixedPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + const [flexPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + + const isMobile = useIsWithinBreakpoints(['xs']); + const layoutMode = isMobile ? ResizableLayoutMode.Static : ResizableLayoutMode.Resizable; + const layoutDirection = isMobile + ? ResizableLayoutDirection.Vertical + : ResizableLayoutDirection.Horizontal; + + const fullWidthAndHeightCss = css` + position: relative; + width: 100%; + height: 100%; + `; + const panelBaseCss = css` + ${fullWidthAndHeightCss} + padding: 20px; + `; + const fixedPanelCss = css` + ${panelBaseCss} + background-color: rgb(255 0 0 / 30%); + `; + const flexPanelCss = css` + ${panelBaseCss} + background-color: rgb(0 0 255 / 30%); + `; + + return ( +
+ +
+ This is the fixed width panel. It will remain the same size when resizing the window until + the flexible panel reaches its minimum size. +
+
+ +
+ This is the flexible width panel. It will resize as the window resizes until it reaches + its minimum size. +
+
+ } + flexPanel={} + onFixedPanelSizeChange={setFixedPanelSize} + /> +
+ ); +}; +``` diff --git a/packages/kbn-resizable-layout/index.ts b/packages/kbn-resizable-layout/index.ts new file mode 100644 index 00000000000000..d3106dbf4f3282 --- /dev/null +++ b/packages/kbn-resizable-layout/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { withSuspense } from '@kbn/shared-ux-utility'; +import { lazy } from 'react'; + +export { ResizableLayoutMode, ResizableLayoutDirection } from './types'; +export type { ResizableLayoutProps } from './src/resizable_layout'; +export const ResizableLayout = withSuspense(lazy(() => import('./src/resizable_layout'))); diff --git a/src/plugins/unified_histogram/public/panels/index.ts b/packages/kbn-resizable-layout/jest.config.js similarity index 74% rename from src/plugins/unified_histogram/public/panels/index.ts rename to packages/kbn-resizable-layout/jest.config.js index ba3e73cb5a35ae..7909efadcc41ba 100644 --- a/src/plugins/unified_histogram/public/panels/index.ts +++ b/packages/kbn-resizable-layout/jest.config.js @@ -6,4 +6,8 @@ * Side Public License, v 1. */ -export { Panels, PANELS_MODE } from './panels'; +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-resizable-layout'], +}; diff --git a/packages/kbn-resizable-layout/kibana.jsonc b/packages/kbn-resizable-layout/kibana.jsonc new file mode 100644 index 00000000000000..b578e1b774dcc4 --- /dev/null +++ b/packages/kbn-resizable-layout/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-common", + "id": "@kbn/resizable-layout", + "description": "A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts.", + "owner": "@elastic/kibana-data-discovery" +} diff --git a/packages/kbn-resizable-layout/package.json b/packages/kbn-resizable-layout/package.json new file mode 100644 index 00000000000000..4f925688a84b40 --- /dev/null +++ b/packages/kbn-resizable-layout/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/resizable-layout", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-resizable-layout/src/panels_resizable.test.tsx b/packages/kbn-resizable-layout/src/panels_resizable.test.tsx new file mode 100644 index 00000000000000..3ea2ccc87aaebb --- /dev/null +++ b/packages/kbn-resizable-layout/src/panels_resizable.test.tsx @@ -0,0 +1,246 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ReactWrapper } from 'enzyme'; +import { mount } from 'enzyme'; +import { ReactElement, useState } from 'react'; +import React from 'react'; +import { PanelsResizable } from './panels_resizable'; +import { act } from 'react-dom/test-utils'; + +const containerHeight = 1000; +const containerWidth = 500; +const fixedPanelId = 'fixedPanel'; + +jest.mock('@elastic/eui', () => ({ + ...jest.requireActual('@elastic/eui'), + useResizeObserver: jest.fn(), + useGeneratedHtmlId: jest.fn(() => fixedPanelId), +})); + +import * as eui from '@elastic/eui'; +import { waitFor } from '@testing-library/dom'; +import { ResizableLayoutDirection } from '../types'; + +describe('Panels resizable', () => { + const mountComponent = ({ + className = '', + direction = ResizableLayoutDirection.Vertical, + container = null, + initialFixedPanelSize = 0, + minFixedPanelSize = 0, + minFlexPanelSize = 0, + fixedPanel = <>, + flexPanel = <>, + attachTo, + onFixedPanelSizeChange = jest.fn(), + }: { + className?: string; + direction?: ResizableLayoutDirection; + container?: HTMLElement | null; + initialFixedPanelSize?: number; + minFixedPanelSize?: number; + minFlexPanelSize?: number; + fixedPanel?: ReactElement; + flexPanel?: ReactElement; + attachTo?: HTMLElement; + onFixedPanelSizeChange?: (fixedPanelSize: number) => void; + }) => { + const PanelsWrapper = ({ fixedPanelSize }: { fixedPanelSize?: number }) => { + const [panelSizes, setPanelSizes] = useState({ + fixedPanelSizePct: 50, + flexPanelSizePct: 50, + }); + + return ( + + ); + }; + + return mount(, attachTo ? { attachTo } : undefined); + }; + + const expectCorrectPanelSizes = ( + component: ReactWrapper, + currentContainerSize: number, + fixedPanelSize: number + ) => { + const fixedPanelSizePct = (fixedPanelSize / currentContainerSize) * 100; + expect( + component.find('[data-test-subj="resizableLayoutResizablePanelFixed"]').at(0).prop('size') + ).toBe(fixedPanelSizePct); + expect( + component.find('[data-test-subj="resizableLayoutResizablePanelFlex"]').at(0).prop('size') + ).toBe(100 - fixedPanelSizePct); + }; + + const forceRender = (component: ReactWrapper) => { + component.setProps({}).update(); + }; + + beforeEach(() => { + jest + .spyOn(eui, 'useResizeObserver') + .mockReturnValue({ height: containerHeight, width: containerWidth }); + }); + + it('should render both panels', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ fixedPanel, flexPanel }); + expect(component.contains(fixedPanel)).toBe(true); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should set the initial sizes of both panels', () => { + const initialFixedPanelSize = 200; + const component = mountComponent({ initialFixedPanelSize }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + }); + + it('should set the correct sizes of both panels when the panels are resized', () => { + const initialFixedPanelSize = 200; + const onFixedPanelSizeChange = jest.fn((fixedPanelSize) => { + component.setProps({ fixedPanelSize }).update(); + }); + const component = mountComponent({ initialFixedPanelSize, onFixedPanelSizeChange }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + const newFixedPanelSizePct = 30; + const onPanelSizeChange = component + .find('[data-test-subj="resizableLayoutResizableContainer"]') + .at(0) + .prop('onPanelWidthChange') as Function; + act(() => { + onPanelSizeChange({ [fixedPanelId]: newFixedPanelSizePct }); + }); + forceRender(component); + const newFixedPanelSize = (newFixedPanelSizePct / 100) * containerHeight; + expect(onFixedPanelSizeChange).toHaveBeenCalledWith(newFixedPanelSize); + expectCorrectPanelSizes(component, containerHeight, newFixedPanelSize); + }); + + it('should maintain the size of the fixed panel and resize the flex panel when the container size changes', () => { + const initialFixedPanelSize = 200; + const component = mountComponent({ initialFixedPanelSize }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + const newContainerSize = 2000; + jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerSize, width: 0 }); + forceRender(component); + expectCorrectPanelSizes(component, newContainerSize, initialFixedPanelSize); + }); + + it('should resize the fixed panel once the flex panel is at its minimum size', () => { + const initialFixedPanelSize = 500; + const minFixedPanelSize = 100; + const minFlexPanelSize = 100; + const component = mountComponent({ + initialFixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + const newContainerSize = 400; + jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerSize, width: 0 }); + forceRender(component); + expectCorrectPanelSizes(component, newContainerSize, newContainerSize - minFlexPanelSize); + jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: containerHeight, width: 0 }); + forceRender(component); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + }); + + it('should maintain the minimum sizes of both panels when the container is too small to fit them', () => { + const initialFixedPanelSize = 500; + const minFixedPanelSize = 100; + const minFlexPanelSize = 150; + const component = mountComponent({ + initialFixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + const newContainerSize = 200; + jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerSize, width: 0 }); + forceRender(component); + expect( + component.find('[data-test-subj="resizableLayoutResizablePanelFixed"]').at(0).prop('size') + ).toBe((minFixedPanelSize / newContainerSize) * 100); + expect( + component.find('[data-test-subj="resizableLayoutResizablePanelFlex"]').at(0).prop('size') + ).toBe((minFlexPanelSize / newContainerSize) * 100); + jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: containerHeight, width: 0 }); + forceRender(component); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + }); + + it('should blur the resize button after a resize', async () => { + const attachTo = document.createElement('div'); + document.body.appendChild(attachTo); + const component = mountComponent({ attachTo }); + const getContainer = () => + component.find('[data-test-subj="resizableLayoutResizableContainer"]').at(0); + const resizeButton = component.find('button[data-test-subj="resizableLayoutResizableButton"]'); + act(() => { + const onResizeStart = getContainer().prop('onResizeStart') as Function; + onResizeStart('pointer'); + }); + (resizeButton.getDOMNode() as HTMLElement).focus(); + forceRender(component); + act(() => { + const onResizeEnd = getContainer().prop('onResizeEnd') as Function; + onResizeEnd(); + }); + expect(resizeButton.getDOMNode()).toHaveFocus(); + await waitFor(() => { + expect(resizeButton.getDOMNode()).not.toHaveFocus(); + }); + }); + + it('should pass direction "vertical" to EuiResizableContainer when direction is ResizableLayoutDirection.Vertical', () => { + const component = mountComponent({ direction: ResizableLayoutDirection.Vertical }); + expect( + component.find('[data-test-subj="resizableLayoutResizableContainer"]').at(0).prop('direction') + ).toBe('vertical'); + }); + + it('should pass direction "horizontal" to EuiResizableContainer when direction is ResizableLayoutDirection.Horizontal', () => { + const component = mountComponent({ direction: ResizableLayoutDirection.Horizontal }); + expect( + component.find('[data-test-subj="resizableLayoutResizableContainer"]').at(0).prop('direction') + ).toBe('horizontal'); + }); + + it('should use containerHeight when direction is ResizableLayoutDirection.Vertical', () => { + const initialFixedPanelSize = 200; + const component = mountComponent({ + direction: ResizableLayoutDirection.Vertical, + initialFixedPanelSize, + }); + expectCorrectPanelSizes(component, containerHeight, initialFixedPanelSize); + }); + + it('should use containerWidth when direction is ResizableLayoutDirection.Horizontal', () => { + const initialFixedPanelSize = 200; + const component = mountComponent({ + direction: ResizableLayoutDirection.Horizontal, + initialFixedPanelSize, + }); + expectCorrectPanelSizes(component, containerWidth, initialFixedPanelSize); + }); +}); diff --git a/packages/kbn-resizable-layout/src/panels_resizable.tsx b/packages/kbn-resizable-layout/src/panels_resizable.tsx new file mode 100644 index 00000000000000..968e5203047fe7 --- /dev/null +++ b/packages/kbn-resizable-layout/src/panels_resizable.tsx @@ -0,0 +1,228 @@ +/* + * Copyright 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 { EuiResizableContainer, useGeneratedHtmlId, useResizeObserver } from '@elastic/eui'; +import type { ResizeTrigger } from '@elastic/eui/src/components/resizable_container/types'; +import { css } from '@emotion/react'; +import { isEqual, round } from 'lodash'; +import type { ReactElement } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; +import { ResizableLayoutDirection } from '../types'; +import { getContainerSize, percentToPixels, pixelsToPercent } from './utils'; + +export const PanelsResizable = ({ + className, + direction, + container, + fixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + panelSizes, + fixedPanel, + flexPanel, + resizeButtonClassName, + ['data-test-subj']: dataTestSubj = 'resizableLayout', + onFixedPanelSizeChange, + setPanelSizes, +}: { + className?: string; + direction: ResizableLayoutDirection; + container: HTMLElement | null; + fixedPanelSize: number; + minFixedPanelSize: number; + minFlexPanelSize: number; + panelSizes: { + fixedPanelSizePct: number; + flexPanelSizePct: number; + }; + fixedPanel: ReactElement; + flexPanel: ReactElement; + resizeButtonClassName?: string; + ['data-test-subj']?: string; + onFixedPanelSizeChange?: (fixedPanelSize: number) => void; + setPanelSizes: (panelSizes: { fixedPanelSizePct: number; flexPanelSizePct: number }) => void; +}) => { + const fixedPanelId = useGeneratedHtmlId({ prefix: 'fixedPanel' }); + const { height: containerHeight, width: containerWidth } = useResizeObserver(container); + const containerSize = getContainerSize(direction, containerWidth, containerHeight); + + // EuiResizableContainer doesn't work properly when used with react-reverse-portal and + // will cancel the resize. To work around this we keep track of when resizes start and + // end to toggle the rendering of a transparent overlay which prevents the cancellation. + // EUI issue: https://github.com/elastic/eui/issues/6199 + const [resizeWithPortalsHackIsResizing, setResizeWithPortalsHackIsResizing] = useState(false); + const enableResizeWithPortalsHack = useCallback( + () => setResizeWithPortalsHackIsResizing(true), + [] + ); + const disableResizeWithPortalsHack = useCallback( + () => setResizeWithPortalsHackIsResizing(false), + [] + ); + const defaultButtonCss = css` + z-index: 3; + `; + const resizeWithPortalsHackButtonCss = css` + z-index: 4; + `; + const resizeWithPortalsHackOverlayCss = css` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 3; + `; + + // We convert the top panel size from a percentage of the container size + // to a pixel value and emit the change to the parent component. We also convert + // the pixel value back to a percentage before updating the panel sizes to avoid + // rounding issues with the isEqual check in the effect below. + const onPanelSizeChange = useCallback( + ({ [fixedPanelId]: currentFixedPanelSize }: { [key: string]: number }) => { + const newFixedPanelSizePx = percentToPixels(containerSize, currentFixedPanelSize); + const newFixedPanelSizePct = pixelsToPercent(containerSize, newFixedPanelSizePx); + + setPanelSizes({ + fixedPanelSizePct: round(newFixedPanelSizePct, 4), + flexPanelSizePct: round(100 - newFixedPanelSizePct, 4), + }); + + onFixedPanelSizeChange?.(newFixedPanelSizePx); + }, + [fixedPanelId, containerSize, setPanelSizes, onFixedPanelSizeChange] + ); + + // This effect will update the panel sizes based on the top panel size whenever + // it or the container size changes. This allows us to keep the size of the + // top panel fixed when the window is resized. + useEffect(() => { + if (!containerSize) { + return; + } + + let fixedPanelSizePct: number; + let flexPanelSizePct: number; + + // If the container size is less than the minimum main content size + // plus the current top panel size, then we need to make some adjustments. + if (containerSize < minFlexPanelSize + fixedPanelSize) { + const newFixedPanelSize = containerSize - minFlexPanelSize; + + // Try to make the top panel size fit within the container, but if it + // doesn't then just use the minimum sizes. + if (newFixedPanelSize < minFixedPanelSize) { + fixedPanelSizePct = pixelsToPercent(containerSize, minFixedPanelSize); + flexPanelSizePct = pixelsToPercent(containerSize, minFlexPanelSize); + } else { + fixedPanelSizePct = pixelsToPercent(containerSize, newFixedPanelSize); + flexPanelSizePct = 100 - fixedPanelSizePct; + } + } else { + fixedPanelSizePct = pixelsToPercent(containerSize, fixedPanelSize); + flexPanelSizePct = 100 - fixedPanelSizePct; + } + + const newPanelSizes = { + fixedPanelSizePct: round(fixedPanelSizePct, 4), + flexPanelSizePct: round(flexPanelSizePct, 4), + }; + + // Skip updating the panel sizes if they haven't changed + // since onPanelSizeChange will also trigger this effect. + if (!isEqual(panelSizes, newPanelSizes)) { + setPanelSizes(newPanelSizes); + } + }, [ + containerSize, + fixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + panelSizes, + setPanelSizes, + ]); + + const onResizeStart = useCallback( + (trigger: ResizeTrigger) => { + if (trigger !== 'pointer') { + return; + } + + enableResizeWithPortalsHack(); + }, + [enableResizeWithPortalsHack] + ); + + const onResizeEnd = useCallback(() => { + if (!resizeWithPortalsHackIsResizing) { + return; + } + + // We don't want the resize button to retain focus after the resize is complete, + // but EuiResizableContainer will force focus it onClick. To work around this we + // use setTimeout to wait until after onClick has been called before blurring. + if (document.activeElement instanceof HTMLElement) { + const button = document.activeElement; + setTimeout(() => { + button.blur(); + }); + } + + disableResizeWithPortalsHack(); + }, [disableResizeWithPortalsHack, resizeWithPortalsHackIsResizing]); + + // Don't render EuiResizableContainer until we have have valid + // panel sizes or it can cause the resize functionality to break. + if (!panelSizes.fixedPanelSizePct && !panelSizes.flexPanelSizePct) { + return null; + } + + return ( + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + {fixedPanel} + + + + {flexPanel} + + {resizeWithPortalsHackIsResizing ?
: <>} + + )} + + ); +}; diff --git a/packages/kbn-resizable-layout/src/panels_static.test.tsx b/packages/kbn-resizable-layout/src/panels_static.test.tsx new file mode 100644 index 00000000000000..7b33c5d2f12d70 --- /dev/null +++ b/packages/kbn-resizable-layout/src/panels_static.test.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiFlexGroup } from '@elastic/eui'; +import { mount } from 'enzyme'; +import type { ReactElement } from 'react'; +import React from 'react'; +import { ResizableLayoutDirection } from '../types'; +import { PanelsStatic } from './panels_static'; + +describe('Panels static', () => { + const mountComponent = ({ + direction = ResizableLayoutDirection.Vertical, + hideFixedPanel = false, + fixedPanel = <>, + flexPanel = <>, + }: { + direction?: ResizableLayoutDirection; + hideFixedPanel?: boolean; + fixedPanel: ReactElement; + flexPanel: ReactElement; + }) => { + return mount( + + ); + }; + + it('should render both panels when hideFixedPanel is false', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ fixedPanel, flexPanel }); + expect(component.contains(fixedPanel)).toBe(true); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should render only flex panel when hideFixedPanel is true', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ hideFixedPanel: true, fixedPanel, flexPanel }); + expect(component.contains(fixedPanel)).toBe(false); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should pass direction "column" to EuiFlexGroup when direction is ResizableLayoutDirection.Vertical', () => { + const component = mountComponent({ + direction: ResizableLayoutDirection.Vertical, + fixedPanel: <>, + flexPanel: <>, + }); + expect(component.find(EuiFlexGroup).prop('direction')).toBe('column'); + }); + + it('should pass direction "row" to EuiFlexGroup when direction is ResizableLayoutDirection.Horizontal', () => { + const component = mountComponent({ + direction: ResizableLayoutDirection.Horizontal, + fixedPanel: <>, + flexPanel: <>, + }); + expect(component.find(EuiFlexGroup).prop('direction')).toBe('row'); + }); +}); diff --git a/src/plugins/unified_histogram/public/panels/panels_fixed.tsx b/packages/kbn-resizable-layout/src/panels_static.tsx similarity index 68% rename from src/plugins/unified_histogram/public/panels/panels_fixed.tsx rename to packages/kbn-resizable-layout/src/panels_static.tsx index 1b7d8bf9bf68ec..7ddc18fc6ce008 100644 --- a/src/plugins/unified_histogram/public/panels/panels_fixed.tsx +++ b/packages/kbn-resizable-layout/src/panels_static.tsx @@ -10,37 +10,43 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { css } from '@emotion/react'; import type { ReactElement } from 'react'; import React from 'react'; +import { ResizableLayoutDirection } from '../types'; -export const PanelsFixed = ({ +export const PanelsStatic = ({ className, - hideTopPanel, - topPanel, - mainPanel, + direction, + hideFixedPanel, + fixedPanel, + flexPanel, }: { className?: string; - hideTopPanel?: boolean; - topPanel: ReactElement; - mainPanel: ReactElement; + direction: ResizableLayoutDirection; + hideFixedPanel?: boolean; + fixedPanel: ReactElement; + flexPanel: ReactElement; }) => { // By default a flex item has overflow: visible, min-height: auto, and min-width: auto. // This can cause the item to overflow the flexbox parent when its content is too large. // Setting the overflow to something other than visible (e.g. auto) resets the min-height // and min-width to 0 and makes the item respect the flexbox parent's size. // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size - const mainPanelCss = css` + const flexPanelCss = css` overflow: auto; `; return ( - {!hideTopPanel && {topPanel}} - {mainPanel} + {!hideFixedPanel && {fixedPanel}} + {flexPanel} ); }; diff --git a/packages/kbn-resizable-layout/src/resizable_layout.test.tsx b/packages/kbn-resizable-layout/src/resizable_layout.test.tsx new file mode 100644 index 00000000000000..dbd3186bc2c3f9 --- /dev/null +++ b/packages/kbn-resizable-layout/src/resizable_layout.test.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { mount } from 'enzyme'; +import type { ReactElement } from 'react'; +import React from 'react'; +import ResizableLayout from './resizable_layout'; +import { PanelsResizable } from './panels_resizable'; +import { PanelsStatic } from './panels_static'; +import { ResizableLayoutDirection, ResizableLayoutMode } from '../types'; + +jest.mock('@elastic/eui', () => ({ + ...jest.requireActual('@elastic/eui'), + useResizeObserver: jest.fn(() => ({ width: 1000, height: 1000 })), +})); + +describe('ResizableLayout component', () => { + const mountComponent = ({ + mode = ResizableLayoutMode.Resizable, + container = null, + initialFixedPanelSize = 200, + minFixedPanelSize = 100, + minFlexPanelSize = 100, + fixedPanel = <>, + flexPanel = <>, + }: { + mode?: ResizableLayoutMode; + container?: HTMLElement | null; + initialFixedPanelSize?: number; + minFixedPanelSize?: number; + minFlexPanelSize?: number; + flexPanel?: ReactElement; + fixedPanel?: ReactElement; + }) => { + return mount( + + ); + }; + + it('should show PanelsFixed when mode is ResizableLayoutMode.Single', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ mode: ResizableLayoutMode.Single, fixedPanel, flexPanel }); + expect(component.find(PanelsStatic).exists()).toBe(true); + expect(component.find(PanelsResizable).exists()).toBe(false); + expect(component.contains(fixedPanel)).toBe(false); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should show PanelsFixed when mode is ResizableLayoutMode.Static', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ mode: ResizableLayoutMode.Static, fixedPanel, flexPanel }); + expect(component.find(PanelsStatic).exists()).toBe(true); + expect(component.find(PanelsResizable).exists()).toBe(false); + expect(component.contains(fixedPanel)).toBe(true); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should show PanelsResizable when mode is ResizableLayoutMode.Resizable', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ + mode: ResizableLayoutMode.Resizable, + fixedPanel, + flexPanel, + }); + expect(component.find(PanelsStatic).exists()).toBe(false); + expect(component.find(PanelsResizable).exists()).toBe(true); + expect(component.contains(fixedPanel)).toBe(true); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should pass true for hideFixedPanel when mode is ResizableLayoutMode.Single', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ mode: ResizableLayoutMode.Single, fixedPanel, flexPanel }); + expect(component.find(PanelsStatic).prop('hideFixedPanel')).toBe(true); + expect(component.contains(fixedPanel)).toBe(false); + expect(component.contains(flexPanel)).toBe(true); + }); + + it('should pass false for hideFixedPanel when mode is ResizableLayoutMode.Static', () => { + const fixedPanel =
; + const flexPanel =
; + const component = mountComponent({ mode: ResizableLayoutMode.Static, fixedPanel, flexPanel }); + expect(component.find(PanelsStatic).prop('hideFixedPanel')).toBe(false); + expect(component.contains(fixedPanel)).toBe(true); + expect(component.contains(flexPanel)).toBe(true); + }); +}); diff --git a/packages/kbn-resizable-layout/src/resizable_layout.tsx b/packages/kbn-resizable-layout/src/resizable_layout.tsx new file mode 100644 index 00000000000000..435d69cdcc8621 --- /dev/null +++ b/packages/kbn-resizable-layout/src/resizable_layout.tsx @@ -0,0 +1,130 @@ +/* + * Copyright 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 { ReactElement, useState } from 'react'; +import React from 'react'; +import { round } from 'lodash'; +import { PanelsResizable } from './panels_resizable'; +import { PanelsStatic } from './panels_static'; +import { ResizableLayoutDirection, ResizableLayoutMode } from '../types'; +import { getContainerSize, pixelsToPercent } from './utils'; + +export interface ResizableLayoutProps { + /** + * Class name for the layout container + */ + className?: string; + /** + * The current layout mode + */ + mode: ResizableLayoutMode; + /** + * The current layout direction + */ + direction: ResizableLayoutDirection; + /** + * The parent container element, used to calculate the layout size + */ + container: HTMLElement | null; + /** + * Current size of the fixed panel in pixels + */ + fixedPanelSize: number; + /** + * Minimum size of the fixed panel in pixels + */ + minFixedPanelSize: number; + /** + * Minimum size of the flex panel in pixels + */ + minFlexPanelSize: number; + /** + * The fixed panel + */ + fixedPanel: ReactElement; + /** + * The flex panel + */ + flexPanel: ReactElement; + /** + * Class name for the resize button + */ + resizeButtonClassName?: string; + /** + * Test subject for the layout container + */ + ['data-test-subj']?: string; + /** + * Callback when the fixed panel size changes, receives the new size in pixels + */ + onFixedPanelSizeChange?: (fixedPanelSize: number) => void; +} + +const staticModes = [ResizableLayoutMode.Single, ResizableLayoutMode.Static]; + +const ResizableLayout = ({ + className, + mode, + direction, + container, + fixedPanelSize, + minFixedPanelSize, + minFlexPanelSize, + fixedPanel, + flexPanel, + resizeButtonClassName, + ['data-test-subj']: dataTestSubj, + onFixedPanelSizeChange, +}: ResizableLayoutProps) => { + const panelsProps = { className, fixedPanel, flexPanel }; + const [panelSizes, setPanelSizes] = useState(() => { + if (!container) { + return { fixedPanelSizePct: 0, flexPanelSizePct: 0 }; + } + + const { width, height } = container.getBoundingClientRect(); + const initialContainerSize = getContainerSize(direction, width, height); + + if (!initialContainerSize) { + return { fixedPanelSizePct: 0, flexPanelSizePct: 0 }; + } + + const fixedPanelSizePct = pixelsToPercent(initialContainerSize, fixedPanelSize); + const flexPanelSizePct = 100 - fixedPanelSizePct; + + return { + fixedPanelSizePct: round(fixedPanelSizePct, 4), + flexPanelSizePct: round(flexPanelSizePct, 4), + }; + }); + + return staticModes.includes(mode) ? ( + + ) : ( + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default ResizableLayout; diff --git a/packages/kbn-resizable-layout/src/utils.test.ts b/packages/kbn-resizable-layout/src/utils.test.ts new file mode 100644 index 00000000000000..31d7cf6d7a16df --- /dev/null +++ b/packages/kbn-resizable-layout/src/utils.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ResizableLayoutDirection } from '../types'; +import { getContainerSize, percentToPixels, pixelsToPercent } from './utils'; + +describe('getContainerSize', () => { + it('should return the width when direction is horizontal', () => { + expect(getContainerSize(ResizableLayoutDirection.Horizontal, 100, 200)).toBe(100); + }); + + it('should return the height when direction is vertical', () => { + expect(getContainerSize(ResizableLayoutDirection.Vertical, 100, 200)).toBe(200); + }); +}); + +describe('percentToPixels', () => { + it('should convert percentage to pixels', () => { + expect(percentToPixels(250, 50)).toBe(125); + }); +}); + +describe('pixelsToPercent', () => { + it('should convert pixels to percentage', () => { + expect(pixelsToPercent(250, 125)).toBe(50); + }); + + it('should clamp percentage to 0 when pixels is negative', () => { + expect(pixelsToPercent(250, -125)).toBe(0); + }); + + it('should clamp percentage to 100 when pixels is greater than container size', () => { + expect(pixelsToPercent(250, 500)).toBe(100); + }); +}); diff --git a/packages/kbn-resizable-layout/src/utils.ts b/packages/kbn-resizable-layout/src/utils.ts new file mode 100644 index 00000000000000..b0f6078b88a2ac --- /dev/null +++ b/packages/kbn-resizable-layout/src/utils.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { clamp } from 'lodash'; +import { ResizableLayoutDirection } from '../types'; + +export const percentToPixels = (containerSize: number, percentage: number) => + Math.round(containerSize * (percentage / 100)); + +export const pixelsToPercent = (containerSize: number, pixels: number) => + clamp((pixels / containerSize) * 100, 0, 100); + +export const getContainerSize = ( + direction: ResizableLayoutDirection, + width: number, + height: number +) => (direction === ResizableLayoutDirection.Vertical ? height : width); diff --git a/packages/kbn-resizable-layout/tsconfig.json b/packages/kbn-resizable-layout/tsconfig.json new file mode 100644 index 00000000000000..28cd6625b53881 --- /dev/null +++ b/packages/kbn-resizable-layout/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["target/**/*"], + "kbn_references": [ + "@kbn/shared-ux-utility", + ] +} diff --git a/packages/kbn-resizable-layout/types.ts b/packages/kbn-resizable-layout/types.ts new file mode 100644 index 00000000000000..3d556431148013 --- /dev/null +++ b/packages/kbn-resizable-layout/types.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export enum ResizableLayoutMode { + /** + * Single panel mode -- hides the fixed panel + */ + Single = 'single', + /** + * Static mode -- prevents resizing + */ + Static = 'static', + /** + * Resizable mode -- allows resizing + */ + Resizable = 'resizable', +} + +export enum ResizableLayoutDirection { + /** + * Horizontal layout -- panels are side by side + */ + Horizontal = 'horizontal', + /** + * Vertical layout -- panels are stacked + */ + Vertical = 'vertical', +} diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.scss b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.scss index b646d60ec3b0fa..48fb44f1663e37 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.scss +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.scss @@ -3,7 +3,6 @@ margin: 0 !important; flex-grow: 1; padding: 0; - width: $euiSize * 19; height: 100%; &--collapsed { @@ -11,6 +10,14 @@ padding: $euiSizeS $euiSizeS 0; } + &.unifiedFieldListSidebar--fullWidth { + min-width: 0 !important; + } + + &:not(.unifiedFieldListSidebar--fullWidth) { + width: $euiSize * 19; + } + @include euiBreakpoint('xs', 's') { width: 100%; padding: $euiSize; diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx index fb90e2b36d39e2..4bc54069336b0a 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx @@ -59,6 +59,11 @@ export type UnifiedFieldListSidebarCustomizableProps = Pick< */ showFieldList?: boolean; + /** + * Make the field list full width + */ + fullWidth?: boolean; + /** * Compressed view */ @@ -145,6 +150,7 @@ export const UnifiedFieldListSidebarComponent: React.FC = { className: classnames('unifiedFieldListSidebar', { 'unifiedFieldListSidebar--collapsed': isSidebarCollapsed, + ['unifiedFieldListSidebar--fullWidth']: fullWidth, }), 'aria-label': i18n.translate( 'unifiedFieldList.fieldListSidebar.indexAndFieldsSectionAriaLabel', diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx index 520a64f8d69b0b..32dd400f2d6fd2 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx @@ -30,6 +30,7 @@ import { EuiShowFor, EuiTitle, } from '@elastic/eui'; +import { BehaviorSubject, Observable } from 'rxjs'; import { useExistingFieldsFetcher, type ExistingFieldsFetcher, @@ -49,6 +50,7 @@ import type { } from '../../types'; export interface UnifiedFieldListSidebarContainerApi { + isSidebarCollapsed$: Observable; refetchFieldsExistenceInfo: ExistingFieldsFetcher['refetchFieldsExistenceInfo']; closeFieldListFlyout: () => void; // no user permission or missing dataViewFieldEditor service will result in `undefined` API methods @@ -121,6 +123,7 @@ const UnifiedFieldListSidebarContainer = forwardRef< const { data, dataViewFieldEditor } = services; const [isFieldListFlyoutVisible, setIsFieldListFlyoutVisible] = useState(false); const { isSidebarCollapsed, onToggleSidebar } = useSidebarToggle({ stateService }); + const [isSidebarCollapsed$] = useState(() => new BehaviorSubject(isSidebarCollapsed)); const canEditDataView = Boolean(dataViewFieldEditor?.userPermissions.editIndexPattern()) || @@ -222,16 +225,21 @@ const UnifiedFieldListSidebarContainer = forwardRef< }; }, []); + useEffect(() => { + isSidebarCollapsed$.next(isSidebarCollapsed); + }, [isSidebarCollapsed, isSidebarCollapsed$]); + useImperativeHandle( componentRef, () => ({ + isSidebarCollapsed$, refetchFieldsExistenceInfo, closeFieldListFlyout, createField: editField, editField, deleteField, }), - [refetchFieldsExistenceInfo, closeFieldListFlyout, editField, deleteField] + [isSidebarCollapsed$, refetchFieldsExistenceInfo, closeFieldListFlyout, editField, deleteField] ); if (!dataView) { diff --git a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx index d7066306ee8d11..832a37577fc89f 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx @@ -122,7 +122,7 @@ const mountComponent = async ({ columns: [], viewMode: VIEW_MODE.DOCUMENT_LEVEL, onAddFilter: jest.fn(), - resizeRef: { current: null }, + container: null, }; stateContainer.searchSessionManager = createSearchSessionMock(session).searchSessionManager; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx index 42ae4e2c18a5c5..54447ebe06b06f 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { RefObject } from 'react'; +import React from 'react'; import { UnifiedHistogramContainer } from '@kbn/unified-histogram-plugin/public'; import { css } from '@emotion/react'; import useObservable from 'react-use/lib/useObservable'; @@ -17,7 +17,7 @@ import { ResetSearchButton } from './reset_search_button'; import { useAppStateSelector } from '../../services/discover_app_state_container'; export interface DiscoverHistogramLayoutProps extends DiscoverMainContentProps { - resizeRef: RefObject; + container: HTMLElement | null; } const histogramLayoutCss = css` @@ -28,7 +28,7 @@ export const DiscoverHistogramLayout = ({ isPlainRecord, dataView, stateContainer, - resizeRef, + container, ...mainContentProps }: DiscoverHistogramLayoutProps) => { const { dataState } = stateContainer; @@ -53,7 +53,7 @@ export const DiscoverHistogramLayout = ({ {...unifiedHistogramProps} searchSessionId={searchSessionId} requestAdapter={dataState.inspectorAdapters.requests} - resizeRef={resizeRef} + container={container} appendHitsCounter={ savedSearch.id ? ( diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.scss b/src/plugins/discover/public/application/main/components/layout/discover_layout.scss index 8f8f5b8ec8833e..88da97d6f53330 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.scss +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.scss @@ -29,10 +29,24 @@ discover-app { .dscPageBody__contents { overflow: hidden; + height: 100%; +} + +.dscSidebarResizeButton { + background-color: transparent !important; + + &:not(:hover):not(:focus) { + &:before, &:after { + width: 0; + } + } } .dscPageContent__wrapper { overflow: hidden; // Ensures horizontal scroll of table + display: flex; + flex-direction: column; + height: 100%; } .dscPageContent { diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx index ac0906911dde86..d4cfa7e049a46b 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx @@ -41,6 +41,11 @@ import { act } from 'react-dom/test-utils'; import { ErrorCallout } from '../../../../components/common/error_callout'; import * as localStorageModule from 'react-use/lib/useLocalStorage'; +jest.mock('@elastic/eui', () => ({ + ...jest.requireActual('@elastic/eui'), + useResizeObserver: jest.fn(() => ({ width: 1000, height: 1000 })), +})); + jest.spyOn(localStorageModule, 'default'); setHeaderActionMenuMounter(jest.fn()); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 3402bfbce1bcc4..4d5655c012e14d 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ import './discover_layout.scss'; -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -31,6 +31,7 @@ import { } from '@kbn/discover-utils'; import { popularizeField, useColumns } from '@kbn/unified-data-table'; import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import type { UnifiedFieldListSidebarContainerApi } from '@kbn/unified-field-list'; import { useSavedSearchInitial } from '../../services/discover_state_provider'; import { DiscoverStateContainer } from '../../services/discover_state'; import { VIEW_MODE } from '../../../../../common/constants'; @@ -52,6 +53,7 @@ import { SavedSearchURLConflictCallout } from '../../../../components/saved_sear import { DiscoverHistogramLayout } from './discover_histogram_layout'; import { ErrorCallout } from '../../../../components/common/error_callout'; import { addLog } from '../../../../utils/add_log'; +import { DiscoverResizableLayout } from './discover_resizable_layout'; const SidebarMemoized = React.memo(DiscoverSidebarResponsive); const TopNavMemoized = React.memo(DiscoverTopNav); @@ -182,7 +184,8 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { } }, [dataState.error, isPlainRecord]); - const resizeRef = useRef(null); + const [sidebarContainer, setSidebarContainer] = useState(null); + const [mainContainer, setMainContainer] = useState(null); const [{ dragging }] = useDragDropContext(); const draggingFieldName = dragging?.id; @@ -211,7 +214,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { viewMode={viewMode} onAddFilter={onAddFilter as DocViewFilterFn} onFieldEdited={onFieldEdited} - resizeRef={resizeRef} + container={mainContainer} onDropFieldToTable={onDropFieldToTable} /> {resultState === 'loading' && } @@ -221,14 +224,18 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { currentColumns, dataView, isPlainRecord, + mainContainer, onAddFilter, + onDropFieldToTable, onFieldEdited, resultState, stateContainer, viewMode, - onDropFieldToTable, ]); + const [unifiedFieldListSidebarContainerApi, setUnifiedFieldListSidebarContainerApi] = + useState(null); + return ( - - - - - - - - - - {resultState === 'none' ? ( - dataState.error ? ( - - ) : ( - - ) - ) : ( - + + - {mainDisplay} - - )} - - + + + + + + + + } + mainPanel={ +
+ {resultState === 'none' ? ( + dataState.error ? ( + + ) : ( + + ) + ) : ( + + {mainDisplay} + + )} +
+ } + /> +
); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.test.tsx new file mode 100644 index 00000000000000..26aacd8948304b --- /dev/null +++ b/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.test.tsx @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { + ResizableLayout, + ResizableLayoutDirection, + ResizableLayoutMode, +} from '@kbn/resizable-layout'; +import { findTestSubject } from '@kbn/test-jest-helpers'; +import type { UnifiedFieldListSidebarContainerApi } from '@kbn/unified-field-list'; +import { mount } from 'enzyme'; +import { isEqual as mockIsEqual } from 'lodash'; +import React from 'react'; +import { of } from 'rxjs'; +import { DiscoverResizableLayout, SIDEBAR_WIDTH_KEY } from './discover_resizable_layout'; + +const mockSidebarKey = SIDEBAR_WIDTH_KEY; +let mockSidebarWidth: number | undefined; + +jest.mock('react-use/lib/useLocalStorage', () => { + return jest.fn((key: string, initialValue: number) => { + if (key !== mockSidebarKey) { + throw new Error(`Unexpected key: ${key}`); + } + return [mockSidebarWidth ?? initialValue, jest.fn()]; + }); +}); + +let mockIsMobile = false; + +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + return { + ...original, + useIsWithinBreakpoints: jest.fn((breakpoints: string[]) => { + if (!mockIsEqual(breakpoints, ['xs', 's'])) { + throw new Error(`Unexpected breakpoints: ${breakpoints}`); + } + return mockIsMobile; + }), + }; +}); + +describe('DiscoverResizableLayout', () => { + beforeEach(() => { + mockSidebarWidth = undefined; + mockIsMobile = false; + }); + + it('should render sidebarPanel and mainPanel', () => { + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(findTestSubject(wrapper, 'sidebarPanel')).toHaveLength(1); + expect(findTestSubject(wrapper, 'mainPanel')).toHaveLength(1); + }); + + it('should use the default sidebar width when no value is stored in local storage', () => { + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('fixedPanelSize')).toBe(304); + }); + + it('should use the stored sidebar width from local storage', () => { + mockSidebarWidth = 400; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('fixedPanelSize')).toBe(400); + }); + + it('should pass mode ResizableLayoutMode.Resizable when not mobile and sidebar is not collapsed', () => { + mockIsMobile = false; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Resizable); + }); + + it('should pass mode ResizableLayoutMode.Static when mobile', () => { + mockIsMobile = true; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Static); + }); + + it('should pass mode ResizableLayoutMode.Static when not mobile and sidebar is collapsed', () => { + mockIsMobile = false; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Static); + }); + + it('should pass direction ResizableLayoutDirection.Horizontal when not mobile', () => { + mockIsMobile = false; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('direction')).toBe( + ResizableLayoutDirection.Horizontal + ); + }); + + it('should pass direction ResizableLayoutDirection.Vertical when mobile', () => { + mockIsMobile = true; + const wrapper = mount( + } + mainPanel={
} + /> + ); + expect(wrapper.find(ResizableLayout).prop('direction')).toBe(ResizableLayoutDirection.Vertical); + }); +}); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.tsx new file mode 100644 index 00000000000000..32491a38d86fd9 --- /dev/null +++ b/src/plugins/discover/public/application/main/components/layout/discover_resizable_layout.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { useEuiTheme, useIsWithinBreakpoints } from '@elastic/eui'; +import { + ResizableLayout, + ResizableLayoutDirection, + ResizableLayoutMode, +} from '@kbn/resizable-layout'; +import type { UnifiedFieldListSidebarContainerApi } from '@kbn/unified-field-list'; +import React, { ReactNode, useState } from 'react'; +import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import useObservable from 'react-use/lib/useObservable'; +import { of } from 'rxjs'; + +export const SIDEBAR_WIDTH_KEY = 'discover:sidebarWidth'; + +export const DiscoverResizableLayout = ({ + container, + unifiedFieldListSidebarContainerApi, + sidebarPanel, + mainPanel, +}: { + container: HTMLElement | null; + unifiedFieldListSidebarContainerApi: UnifiedFieldListSidebarContainerApi | null; + sidebarPanel: ReactNode; + mainPanel: ReactNode; +}) => { + const [sidebarPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + const [mainPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) + ); + + const { euiTheme } = useEuiTheme(); + const minSidebarWidth = euiTheme.base * 13; + const defaultSidebarWidth = euiTheme.base * 19; + const minMainPanelWidth = euiTheme.base * 30; + + const [sidebarWidth, setSidebarWidth] = useLocalStorage(SIDEBAR_WIDTH_KEY, defaultSidebarWidth); + const isSidebarCollapsed = useObservable( + unifiedFieldListSidebarContainerApi?.isSidebarCollapsed$ ?? of(true), + true + ); + + const isMobile = useIsWithinBreakpoints(['xs', 's']); + const layoutMode = + isMobile || isSidebarCollapsed ? ResizableLayoutMode.Static : ResizableLayoutMode.Resizable; + const layoutDirection = isMobile + ? ResizableLayoutDirection.Vertical + : ResizableLayoutDirection.Horizontal; + + return ( + <> + {sidebarPanel} + {mainPanel} + } + flexPanel={} + resizeButtonClassName="dscSidebarResizeButton" + data-test-subj="discoverLayout" + onFixedPanelSizeChange={setSidebarWidth} + /> + + ); +}; diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx index bd2f2c7639e46f..723c19b5b3d990 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx @@ -13,7 +13,7 @@ import { EuiProgress } from '@elastic/eui'; import { getDataTableRecords, realHits } from '../../../../__fixtures__/real_hits'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import React from 'react'; +import React, { useState } from 'react'; import { DiscoverSidebarResponsive, DiscoverSidebarResponsiveProps, @@ -37,6 +37,7 @@ import { buildDataTableRecord } from '@kbn/discover-utils'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import type { DiscoverCustomizationId } from '../../../../customizations/customization_service'; import type { SearchBarCustomization } from '../../../../customizations'; +import type { UnifiedFieldListSidebarContainerApi } from '@kbn/unified-field-list'; const mockSearchBarCustomization: SearchBarCustomization = { id: 'search_bar', @@ -168,6 +169,8 @@ function getCompProps(options?: { hits?: DataTableRecord[] }): DiscoverSidebarRe trackUiMetric: jest.fn(), onFieldEdited: jest.fn(), onDataViewCreated: jest.fn(), + unifiedFieldListSidebarContainerApi: null, + setUnifiedFieldListSidebarContainerApi: jest.fn(), }; } @@ -199,19 +202,30 @@ async function mountComponent( mockedServices.data.query.getState = jest.fn().mockImplementation(() => appState.getState()); await act(async () => { - comp = await mountWithIntl( + const SidebarWrapper = () => { + const [api, setApi] = useState(null); + return ( + + ); + }; + + comp = mountWithIntl( - + ); // wait for lazy modules await new Promise((resolve) => setTimeout(resolve, 0)); - await comp.update(); + comp.update(); }); - await comp!.update(); + comp!.update(); return comp!; } @@ -251,7 +265,7 @@ describe('discover responsive sidebar', function () { await act(async () => { // wait for lazy modules await new Promise((resolve) => setTimeout(resolve, 0)); - await compLoadingExistence.update(); + compLoadingExistence.update(); }); expect( @@ -273,11 +287,11 @@ describe('discover responsive sidebar', function () { indexPatternTitle: 'test-loaded', existingFieldNames: Object.keys(mockfieldCounts), }); - await compLoadingExistence.update(); + compLoadingExistence.update(); }); await act(async () => { - await compLoadingExistence.update(); + compLoadingExistence.update(); }); expect( @@ -419,11 +433,11 @@ describe('discover responsive sidebar', function () { const availableFields = findTestSubject(comp, 'fieldListGroupedAvailableFields'); await act(async () => { const button = findTestSubject(availableFields, 'field-extension-showDetails'); - await button.simulate('click'); - await comp.update(); + button.simulate('click'); + comp.update(); }); - await comp.update(); + comp.update(); findTestSubject(comp, 'plus-extension-gif').simulate('click'); expect(props.onAddFilter).toHaveBeenCalled(); }); @@ -432,11 +446,11 @@ describe('discover responsive sidebar', function () { const availableFields = findTestSubject(comp, 'fieldListGroupedAvailableFields'); await act(async () => { const button = findTestSubject(availableFields, 'field-extension-showDetails'); - await button.simulate('click'); - await comp.update(); + button.simulate('click'); + comp.update(); }); - await comp.update(); + comp.update(); findTestSubject(comp, 'discoverFieldListPanelAddExistFilter-extension').simulate('click'); expect(props.onAddFilter).toHaveBeenCalledWith('_exists_', 'extension', '+'); }); @@ -450,7 +464,7 @@ describe('discover responsive sidebar', function () { ); await act(async () => { - await findTestSubject(comp, 'fieldListFiltersFieldSearch').simulate('change', { + findTestSubject(comp, 'fieldListFiltersFieldSearch').simulate('change', { target: { value: 'bytes' }, }); }); @@ -471,16 +485,16 @@ describe('discover responsive sidebar', function () { ); await act(async () => { - await findTestSubject(comp, 'fieldListFiltersFieldTypeFilterToggle').simulate('click'); + findTestSubject(comp, 'fieldListFiltersFieldTypeFilterToggle').simulate('click'); }); - await comp.update(); + comp.update(); await act(async () => { - await findTestSubject(comp, 'typeFilter-number').simulate('click'); + findTestSubject(comp, 'typeFilter-number').simulate('click'); }); - await comp.update(); + comp.update(); expect(findTestSubject(comp, 'fieldListGroupedAvailableFields-count').text()).toBe('2'); expect(findTestSubject(comp, 'fieldListGrouped__ariaDescription').text()).toBe( @@ -519,7 +533,7 @@ describe('discover responsive sidebar', function () { await act(async () => { await new Promise((resolve) => setTimeout(resolve, 0)); - await compInTextBasedMode.update(); + compInTextBasedMode.update(); }); expect(findTestSubject(compInTextBasedMode, 'indexPattern-add-field_btn').length).toBe(0); @@ -619,7 +633,7 @@ describe('discover responsive sidebar', function () { ); const addFieldButton = findTestSubject(comp, 'dataView-add-field_btn'); expect(addFieldButton.length).toBe(1); - await addFieldButton.simulate('click'); + addFieldButton.simulate('click'); expect(services.dataViewFieldEditor.openEditor).toHaveBeenCalledTimes(1); }); @@ -630,10 +644,10 @@ describe('discover responsive sidebar', function () { await act(async () => { findTestSubject(availableFields, 'field-bytes').simulate('click'); }); - await comp.update(); + comp.update(); const editFieldButton = findTestSubject(comp, 'discoverFieldListPanelEdit-bytes'); expect(editFieldButton.length).toBe(1); - await editFieldButton.simulate('click'); + editFieldButton.simulate('click'); expect(services.dataViewFieldEditor.openEditor).toHaveBeenCalledTimes(1); }); @@ -662,12 +676,12 @@ describe('discover responsive sidebar', function () { // open flyout await act(async () => { compWithPicker.find('.unifiedFieldListSidebar__mobileButton').last().simulate('click'); - await compWithPicker.update(); + compWithPicker.update(); }); - await compWithPicker.update(); + compWithPicker.update(); // open data view picker - await findTestSubject(compWithPicker, 'dataView-switch-link').simulate('click'); + findTestSubject(compWithPicker, 'dataView-switch-link').simulate('click'); expect(findTestSubject(compWithPicker, 'changeDataViewPopover').length).toBe(1); // check "Add a field" const addFieldButtonInDataViewPicker = findTestSubject( @@ -678,7 +692,7 @@ describe('discover responsive sidebar', function () { // click "Create a data view" const createDataViewButton = findTestSubject(compWithPicker, 'dataview-create-new'); expect(createDataViewButton.length).toBe(1); - await createDataViewButton.simulate('click'); + createDataViewButton.simulate('click'); expect(services.dataViewEditor.openEditor).toHaveBeenCalled(); }); @@ -697,10 +711,10 @@ describe('discover responsive sidebar', function () { .find('.unifiedFieldListSidebar__mobileButton') .last() .simulate('click'); - await compWithPickerInViewerMode.update(); + compWithPickerInViewerMode.update(); }); - await compWithPickerInViewerMode.update(); + compWithPickerInViewerMode.update(); // open data view picker findTestSubject(compWithPickerInViewerMode, 'dataView-switch-link').simulate('click'); expect(findTestSubject(compWithPickerInViewerMode, 'changeDataViewPopover').length).toBe(1); @@ -724,10 +738,10 @@ describe('discover responsive sidebar', function () { await act(async () => { comp.find('.unifiedFieldListSidebar__mobileButton').last().simulate('click'); - await comp.update(); + comp.update(); }); - await comp.update(); + comp.update(); expect(comp.find('[data-test-subj="custom-data-view-picker"]').exists()).toBe(false); }); @@ -741,10 +755,10 @@ describe('discover responsive sidebar', function () { await act(async () => { comp.find('.unifiedFieldListSidebar__mobileButton').last().simulate('click'); - await comp.update(); + comp.update(); }); - await comp.update(); + comp.update(); expect(comp.find('[data-test-subj="custom-data-view-picker"]').exists()).toBe(true); }); diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx index f8352850cb4d4f..3177adefdf49ba 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useReducer, useRef } from 'react'; import { UiCounterMetricType } from '@kbn/analytics'; import { i18n } from '@kbn/i18n'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; @@ -133,6 +133,9 @@ export interface DiscoverSidebarResponsiveProps { * For customization and testing purposes */ fieldListVariant?: UnifiedFieldListSidebarContainerProps['variant']; + + unifiedFieldListSidebarContainerApi: UnifiedFieldListSidebarContainerApi | null; + setUnifiedFieldListSidebarContainerApi: (api: UnifiedFieldListSidebarContainerApi) => void; } /** @@ -153,6 +156,8 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) onChangeDataView, onAddField, onRemoveField, + unifiedFieldListSidebarContainerApi, + setUnifiedFieldListSidebarContainerApi, } = props; const [sidebarState, dispatchSidebarStateAction] = useReducer( discoverSidebarReducer, @@ -161,8 +166,6 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) ); const selectedDataViewRef = useRef(selectedDataView); const showFieldList = sidebarState.status !== DiscoverSidebarReducerStatus.INITIAL; - const [unifiedFieldListSidebarContainerApi, setUnifiedFieldListSidebarContainerApi] = - useState(null); useEffect(() => { const subscription = props.documents$.subscribe((documentState) => { @@ -385,6 +388,7 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) allFields={sidebarState.allFields} showFieldList={showFieldList} workspaceSelectedFieldNames={columns} + fullWidth onAddFieldToWorkspace={onAddFieldToWorkspace} onRemoveFieldFromWorkspace={onRemoveFieldFromWorkspace} onAddFilter={onAddFilter} diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index cb84d95d69f7cc..4c24cbb6140ca8 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -73,7 +73,8 @@ "@kbn/unified-data-table", "@kbn/no-data-page-plugin", "@kbn/rule-data-utils", - "@kbn/global-search-plugin" + "@kbn/global-search-plugin", + "@kbn/resizable-layout" ], "exclude": [ "target/**/*" diff --git a/src/plugins/unified_histogram/public/container/container.test.tsx b/src/plugins/unified_histogram/public/container/container.test.tsx index ea6ef95db55fa1..de62cf599761ba 100644 --- a/src/plugins/unified_histogram/public/container/container.test.tsx +++ b/src/plugins/unified_histogram/public/container/container.test.tsx @@ -33,7 +33,7 @@ describe('UnifiedHistogramContainer', () => { requestAdapter={new RequestAdapter()} searchSessionId={'123'} timeRange={{ from: 'now-15m', to: 'now' }} - resizeRef={{ current: null }} + container={null} /> ); expect(component.update().isEmptyRender()).toBe(true); @@ -62,7 +62,7 @@ describe('UnifiedHistogramContainer', () => { requestAdapter={new RequestAdapter()} searchSessionId={'123'} timeRange={{ from: 'now-15m', to: 'now' }} - resizeRef={{ current: null }} + container={null} /> ); await act(() => new Promise((resolve) => setTimeout(resolve, 0))); diff --git a/src/plugins/unified_histogram/public/container/container.tsx b/src/plugins/unified_histogram/public/container/container.tsx index 74ecf5837c02ee..c65f1e2b43c045 100644 --- a/src/plugins/unified_histogram/public/container/container.tsx +++ b/src/plugins/unified_histogram/public/container/container.tsx @@ -53,7 +53,7 @@ export type UnifiedHistogramContainerProps = { | 'timeRange' | 'relativeTimeRange' | 'columns' - | 'resizeRef' + | 'container' | 'appendHitsCounter' | 'children' | 'onBrushEnd' diff --git a/src/plugins/unified_histogram/public/layout/layout.test.tsx b/src/plugins/unified_histogram/public/layout/layout.test.tsx index f75fa0b1d4b9c7..a12c8cf46430e5 100644 --- a/src/plugins/unified_histogram/public/layout/layout.test.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.test.tsx @@ -13,7 +13,6 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { of } from 'rxjs'; import { Chart } from '../chart'; -import { Panels, PANELS_MODE } from '../panels'; import { UnifiedHistogramChartContext, UnifiedHistogramFetchStatus, @@ -22,6 +21,7 @@ import { import { dataViewWithTimefieldMock } from '../__mocks__/data_view_with_timefield'; import { unifiedHistogramServicesMock } from '../__mocks__/services'; import { UnifiedHistogramLayout, UnifiedHistogramLayoutProps } from './layout'; +import { ResizableLayout, ResizableLayoutMode } from '@kbn/resizable-layout'; let mockBreakpoint = 'l'; @@ -50,7 +50,7 @@ describe('Layout', () => { services = unifiedHistogramServicesMock, hits = createHits(), chart = createChart(), - resizeRef = { current: null }, + container = null, ...rest }: Partial> & { hits?: UnifiedHistogramHitsContext | null; @@ -65,7 +65,7 @@ describe('Layout', () => { services={services} hits={hits ?? undefined} chart={chart ?? undefined} - resizeRef={resizeRef} + container={container} dataView={dataViewWithTimefieldMock} query={{ language: 'kuery', @@ -95,66 +95,66 @@ describe('Layout', () => { }); describe('PANELS_MODE', () => { - it('should set the panels mode to PANELS_MODE.RESIZABLE when viewing on medium screens and above', async () => { + it('should set the layout mode to ResizableLayoutMode.Resizable when viewing on medium screens and above', async () => { const component = await mountComponent(); setBreakpoint(component, 'm'); - expect(component.find(Panels).prop('mode')).toBe(PANELS_MODE.RESIZABLE); + expect(component.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Resizable); }); - it('should set the panels mode to PANELS_MODE.FIXED when viewing on small screens and below', async () => { + it('should set the layout mode to ResizableLayoutMode.Static when viewing on small screens and below', async () => { const component = await mountComponent(); setBreakpoint(component, 's'); - expect(component.find(Panels).prop('mode')).toBe(PANELS_MODE.FIXED); + expect(component.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Static); }); - it('should set the panels mode to PANELS_MODE.FIXED if chart.hidden is true', async () => { + it('should set the layout mode to ResizableLayoutMode.Static if chart.hidden is true', async () => { const component = await mountComponent({ chart: { ...createChart(), hidden: true, }, }); - expect(component.find(Panels).prop('mode')).toBe(PANELS_MODE.FIXED); + expect(component.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Static); }); - it('should set the panels mode to PANELS_MODE.FIXED if chart is undefined', async () => { + it('should set the layout mode to ResizableLayoutMode.Static if chart is undefined', async () => { const component = await mountComponent({ chart: null }); - expect(component.find(Panels).prop('mode')).toBe(PANELS_MODE.FIXED); + expect(component.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Static); }); - it('should set the panels mode to PANELS_MODE.SINGLE if chart and hits are undefined', async () => { + it('should set the layout mode to ResizableLayoutMode.Single if chart and hits are undefined', async () => { const component = await mountComponent({ chart: null, hits: null }); - expect(component.find(Panels).prop('mode')).toBe(PANELS_MODE.SINGLE); + expect(component.find(ResizableLayout).prop('mode')).toBe(ResizableLayoutMode.Single); }); - it('should set a fixed height for Chart when panels mode is PANELS_MODE.FIXED and chart.hidden is false', async () => { + it('should set a fixed height for Chart when layout mode is ResizableLayoutMode.Static and chart.hidden is false', async () => { const component = await mountComponent(); setBreakpoint(component, 's'); - const expectedHeight = component.find(Panels).prop('topPanelHeight'); + const expectedHeight = component.find(ResizableLayout).prop('fixedPanelSize'); expect(component.find(Chart).find('div.euiFlexGroup').first().getDOMNode()).toHaveStyle({ height: `${expectedHeight}px`, }); }); - it('should not set a fixed height for Chart when panels mode is PANELS_MODE.FIXED and chart.hidden is true', async () => { + it('should not set a fixed height for Chart when layout mode is ResizableLayoutMode.Static and chart.hidden is true', async () => { const component = await mountComponent({ chart: { ...createChart(), hidden: true } }); setBreakpoint(component, 's'); - const expectedHeight = component.find(Panels).prop('topPanelHeight'); + const expectedHeight = component.find(ResizableLayout).prop('fixedPanelSize'); expect(component.find(Chart).find('div.euiFlexGroup').first().getDOMNode()).not.toHaveStyle({ height: `${expectedHeight}px`, }); }); - it('should not set a fixed height for Chart when panels mode is PANELS_MODE.FIXED and chart is undefined', async () => { + it('should not set a fixed height for Chart when layout mode is ResizableLayoutMode.Static and chart is undefined', async () => { const component = await mountComponent({ chart: null }); setBreakpoint(component, 's'); - const expectedHeight = component.find(Panels).prop('topPanelHeight'); + const expectedHeight = component.find(ResizableLayout).prop('fixedPanelSize'); expect(component.find(Chart).find('div.euiFlexGroup').first().getDOMNode()).not.toHaveStyle({ height: `${expectedHeight}px`, }); }); - it('should pass undefined for onResetChartHeight to Chart when panels mode is PANELS_MODE.FIXED', async () => { + it('should pass undefined for onResetChartHeight to Chart when layout mode is ResizableLayoutMode.Static', async () => { const component = await mountComponent({ topPanelHeight: 123 }); expect(component.find(Chart).prop('onResetChartHeight')).toBeDefined(); setBreakpoint(component, 's'); @@ -163,28 +163,28 @@ describe('Layout', () => { }); describe('topPanelHeight', () => { - it('should pass a default topPanelHeight to Panels when the topPanelHeight prop is undefined', async () => { + it('should pass a default fixedPanelSize to ResizableLayout when the topPanelHeight prop is undefined', async () => { const component = await mountComponent({ topPanelHeight: undefined }); - expect(component.find(Panels).prop('topPanelHeight')).toBeGreaterThan(0); + expect(component.find(ResizableLayout).prop('fixedPanelSize')).toBeGreaterThan(0); }); - it('should reset the topPanelHeight to the default when onResetChartHeight is called on Chart', async () => { + it('should reset the fixedPanelSize to the default when onResetChartHeight is called on Chart', async () => { const component: ReactWrapper = await mountComponent({ onTopPanelHeightChange: jest.fn((topPanelHeight) => { component.setProps({ topPanelHeight }); }), }); - const defaultTopPanelHeight = component.find(Panels).prop('topPanelHeight'); + const defaultTopPanelHeight = component.find(ResizableLayout).prop('fixedPanelSize'); const newTopPanelHeight = 123; - expect(component.find(Panels).prop('topPanelHeight')).not.toBe(newTopPanelHeight); + expect(component.find(ResizableLayout).prop('fixedPanelSize')).not.toBe(newTopPanelHeight); act(() => { - component.find(Panels).prop('onTopPanelHeightChange')!(newTopPanelHeight); + component.find(ResizableLayout).prop('onFixedPanelSizeChange')!(newTopPanelHeight); }); - expect(component.find(Panels).prop('topPanelHeight')).toBe(newTopPanelHeight); + expect(component.find(ResizableLayout).prop('fixedPanelSize')).toBe(newTopPanelHeight); act(() => { component.find(Chart).prop('onResetChartHeight')!(); }); - expect(component.find(Panels).prop('topPanelHeight')).toBe(defaultTopPanelHeight); + expect(component.find(ResizableLayout).prop('fixedPanelSize')).toBe(defaultTopPanelHeight); }); it('should pass undefined for onResetChartHeight to Chart when the chart is the default height', async () => { diff --git a/src/plugins/unified_histogram/public/layout/layout.tsx b/src/plugins/unified_histogram/public/layout/layout.tsx index 014495427f30a3..d923ea3031a502 100644 --- a/src/plugins/unified_histogram/public/layout/layout.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.tsx @@ -7,8 +7,7 @@ */ import { EuiSpacer, useEuiTheme, useIsWithinBreakpoints } from '@elastic/eui'; -import { PropsWithChildren, ReactElement, RefObject } from 'react'; -import React, { useMemo } from 'react'; +import React, { PropsWithChildren, ReactElement, useMemo, useState } from 'react'; import { Observable } from 'rxjs'; import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; import { css } from '@emotion/css'; @@ -21,9 +20,13 @@ import type { LensSuggestionsApi, Suggestion, } from '@kbn/lens-plugin/public'; -import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; +import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; +import { + ResizableLayout, + ResizableLayoutMode, + ResizableLayoutDirection, +} from '@kbn/resizable-layout'; import { Chart } from '../chart'; -import { Panels, PANELS_MODE } from '../panels'; import type { UnifiedHistogramChartContext, UnifiedHistogramServices, @@ -96,9 +99,9 @@ export interface UnifiedHistogramLayoutProps extends PropsWithChildren */ breakdown?: UnifiedHistogramBreakdownContext; /** - * Ref to the element wrapping the layout which will be used for resize calculations + * The parent container element, used to calculate the layout size */ - resizeRef: RefObject; + container: HTMLElement | null; /** * Current top panel height -- leave undefined to use the default */ @@ -192,7 +195,7 @@ export const UnifiedHistogramLayout = ({ lensEmbeddableOutput$, chart: originalChart, breakdown, - resizeRef, + container, topPanelHeight, appendHitsCounter, disableAutoFetching, @@ -226,14 +229,11 @@ export const UnifiedHistogramLayout = ({ }); const chart = suggestionUnsupported ? undefined : originalChart; - const topPanelNode = useMemo( - () => createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }), - [] + const [topPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) ); - - const mainPanelNode = useMemo( - () => createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }), - [] + const [mainPanelNode] = useState(() => + createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }) ); const isMobile = useIsWithinBreakpoints(['xs', 's']); @@ -252,14 +252,15 @@ export const UnifiedHistogramLayout = ({ const panelsMode = chart || hits ? showFixedPanels - ? PANELS_MODE.FIXED - : PANELS_MODE.RESIZABLE - : PANELS_MODE.SINGLE; + ? ResizableLayoutMode.Static + : ResizableLayoutMode.Resizable + : ResizableLayoutMode.Single; const currentTopPanelHeight = topPanelHeight ?? defaultTopPanelHeight; const onResetChartHeight = useMemo(() => { - return currentTopPanelHeight !== defaultTopPanelHeight && panelsMode === PANELS_MODE.RESIZABLE + return currentTopPanelHeight !== defaultTopPanelHeight && + panelsMode === ResizableLayoutMode.Resizable ? () => onTopPanelHeightChange?.(undefined) : undefined; }, [currentTopPanelHeight, defaultTopPanelHeight, onTopPanelHeightChange, panelsMode]); @@ -305,16 +306,18 @@ export const UnifiedHistogramLayout = ({ /> {children} - } - mainPanel={} - onTopPanelHeightChange={onTopPanelHeightChange} + direction={ResizableLayoutDirection.Vertical} + container={container} + fixedPanelSize={currentTopPanelHeight} + minFixedPanelSize={defaultTopPanelHeight} + minFlexPanelSize={minMainPanelHeight} + fixedPanel={} + flexPanel={} + data-test-subj="unifiedHistogram" + onFixedPanelSizeChange={onTopPanelHeightChange} /> ); diff --git a/src/plugins/unified_histogram/public/panels/panels.test.tsx b/src/plugins/unified_histogram/public/panels/panels.test.tsx deleted file mode 100644 index e0e2de24b4083a..00000000000000 --- a/src/plugins/unified_histogram/public/panels/panels.test.tsx +++ /dev/null @@ -1,95 +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 { mount } from 'enzyme'; -import type { ReactElement, RefObject } from 'react'; -import React from 'react'; -import { Panels, PANELS_MODE } from './panels'; -import { PanelsResizable } from './panels_resizable'; -import { PanelsFixed } from './panels_fixed'; - -describe('Panels component', () => { - const mountComponent = ({ - mode = PANELS_MODE.RESIZABLE, - resizeRef = { current: null }, - initialTopPanelHeight = 200, - minTopPanelHeight = 100, - minMainPanelHeight = 100, - topPanel = <>, - mainPanel = <>, - }: { - mode?: PANELS_MODE; - resizeRef?: RefObject; - initialTopPanelHeight?: number; - minTopPanelHeight?: number; - minMainPanelHeight?: number; - mainPanel?: ReactElement; - topPanel?: ReactElement; - }) => { - return mount( - - ); - }; - - it('should show PanelsFixed when mode is PANELS_MODE.SINGLE', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ mode: PANELS_MODE.SINGLE, topPanel, mainPanel }); - expect(component.find(PanelsFixed).exists()).toBe(true); - expect(component.find(PanelsResizable).exists()).toBe(false); - expect(component.contains(topPanel)).toBe(false); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should show PanelsFixed when mode is PANELS_MODE.FIXED', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ mode: PANELS_MODE.FIXED, topPanel, mainPanel }); - expect(component.find(PanelsFixed).exists()).toBe(true); - expect(component.find(PanelsResizable).exists()).toBe(false); - expect(component.contains(topPanel)).toBe(true); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should show PanelsResizable when mode is PANELS_MODE.RESIZABLE', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ mode: PANELS_MODE.RESIZABLE, topPanel, mainPanel }); - expect(component.find(PanelsFixed).exists()).toBe(false); - expect(component.find(PanelsResizable).exists()).toBe(true); - expect(component.contains(topPanel)).toBe(true); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should pass true for hideTopPanel when mode is PANELS_MODE.SINGLE', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ mode: PANELS_MODE.SINGLE, topPanel, mainPanel }); - expect(component.find(PanelsFixed).prop('hideTopPanel')).toBe(true); - expect(component.contains(topPanel)).toBe(false); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should pass false for hideTopPanel when mode is PANELS_MODE.FIXED', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ mode: PANELS_MODE.FIXED, topPanel, mainPanel }); - expect(component.find(PanelsFixed).prop('hideTopPanel')).toBe(false); - expect(component.contains(topPanel)).toBe(true); - expect(component.contains(mainPanel)).toBe(true); - }); -}); diff --git a/src/plugins/unified_histogram/public/panels/panels.tsx b/src/plugins/unified_histogram/public/panels/panels.tsx deleted file mode 100644 index 609219ab28666e..00000000000000 --- a/src/plugins/unified_histogram/public/panels/panels.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { ReactElement, RefObject } from 'react'; -import React from 'react'; -import { PanelsResizable } from './panels_resizable'; -import { PanelsFixed } from './panels_fixed'; - -export enum PANELS_MODE { - SINGLE = 'single', - FIXED = 'fixed', - RESIZABLE = 'resizable', -} - -export interface PanelsProps { - className?: string; - mode: PANELS_MODE; - resizeRef: RefObject; - topPanelHeight: number; - minTopPanelHeight: number; - minMainPanelHeight: number; - topPanel: ReactElement; - mainPanel: ReactElement; - onTopPanelHeightChange?: (topPanelHeight: number) => void; -} - -const fixedModes = [PANELS_MODE.SINGLE, PANELS_MODE.FIXED]; - -export const Panels = ({ - className, - mode, - resizeRef, - topPanelHeight, - minTopPanelHeight, - minMainPanelHeight, - topPanel, - mainPanel, - onTopPanelHeightChange, -}: PanelsProps) => { - const panelsProps = { className, topPanel, mainPanel }; - - return fixedModes.includes(mode) ? ( - - ) : ( - - ); -}; diff --git a/src/plugins/unified_histogram/public/panels/panels_fixed.test.tsx b/src/plugins/unified_histogram/public/panels/panels_fixed.test.tsx deleted file mode 100644 index e803d0445b1ec1..00000000000000 --- a/src/plugins/unified_histogram/public/panels/panels_fixed.test.tsx +++ /dev/null @@ -1,44 +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 { mount } from 'enzyme'; -import type { ReactElement } from 'react'; -import React from 'react'; -import { PanelsFixed } from './panels_fixed'; - -describe('Panels fixed', () => { - const mountComponent = ({ - hideTopPanel = false, - topPanel = <>, - mainPanel = <>, - }: { - hideTopPanel?: boolean; - topPanel: ReactElement; - mainPanel: ReactElement; - }) => { - return mount( - - ); - }; - - it('should render both panels when hideTopPanel is false', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ topPanel, mainPanel }); - expect(component.contains(topPanel)).toBe(true); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should render only main panel when hideTopPanel is true', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ hideTopPanel: true, topPanel, mainPanel }); - expect(component.contains(topPanel)).toBe(false); - expect(component.contains(mainPanel)).toBe(true); - }); -}); diff --git a/src/plugins/unified_histogram/public/panels/panels_resizable.test.tsx b/src/plugins/unified_histogram/public/panels/panels_resizable.test.tsx deleted file mode 100644 index add0281cfc0fd5..00000000000000 --- a/src/plugins/unified_histogram/public/panels/panels_resizable.test.tsx +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { ReactWrapper } from 'enzyme'; -import { mount } from 'enzyme'; -import type { ReactElement, RefObject } from 'react'; -import React from 'react'; -import { PanelsResizable } from './panels_resizable'; -import { act } from 'react-dom/test-utils'; - -const containerHeight = 1000; -const topPanelId = 'topPanel'; - -jest.mock('@elastic/eui', () => ({ - ...jest.requireActual('@elastic/eui'), - useResizeObserver: jest.fn(), - useGeneratedHtmlId: jest.fn(() => topPanelId), -})); - -import * as eui from '@elastic/eui'; -import { waitFor } from '@testing-library/dom'; - -describe('Panels resizable', () => { - const mountComponent = ({ - className = '', - resizeRef = { current: null }, - initialTopPanelHeight = 0, - minTopPanelHeight = 0, - minMainPanelHeight = 0, - topPanel = <>, - mainPanel = <>, - attachTo, - onTopPanelHeightChange = jest.fn(), - }: { - className?: string; - resizeRef?: RefObject; - initialTopPanelHeight?: number; - minTopPanelHeight?: number; - minMainPanelHeight?: number; - topPanel?: ReactElement; - mainPanel?: ReactElement; - attachTo?: HTMLElement; - onTopPanelHeightChange?: (topPanelHeight: number) => void; - }) => { - return mount( - , - attachTo ? { attachTo } : undefined - ); - }; - - const expectCorrectPanelSizes = ( - component: ReactWrapper, - currentContainerHeight: number, - topPanelHeight: number - ) => { - const topPanelSize = (topPanelHeight / currentContainerHeight) * 100; - expect( - component.find('[data-test-subj="unifiedHistogramResizablePanelTop"]').at(0).prop('size') - ).toBe(topPanelSize); - expect( - component.find('[data-test-subj="unifiedHistogramResizablePanelMain"]').at(0).prop('size') - ).toBe(100 - topPanelSize); - }; - - const forceRender = (component: ReactWrapper) => { - component.setProps({}).update(); - }; - - beforeEach(() => { - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: containerHeight, width: 0 }); - }); - - it('should render both panels', () => { - const topPanel =
; - const mainPanel =
; - const component = mountComponent({ topPanel, mainPanel }); - expect(component.contains(topPanel)).toBe(true); - expect(component.contains(mainPanel)).toBe(true); - }); - - it('should set the initial heights of both panels', () => { - const initialTopPanelHeight = 200; - const component = mountComponent({ initialTopPanelHeight }); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - }); - - it('should set the correct heights of both panels when the panels are resized', () => { - const initialTopPanelHeight = 200; - const onTopPanelHeightChange = jest.fn((topPanelHeight) => { - component.setProps({ topPanelHeight }).update(); - }); - const component = mountComponent({ initialTopPanelHeight, onTopPanelHeightChange }); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - const newTopPanelSize = 30; - const onPanelSizeChange = component - .find('[data-test-subj="unifiedHistogramResizableContainer"]') - .at(0) - .prop('onPanelWidthChange') as Function; - act(() => { - onPanelSizeChange({ [topPanelId]: newTopPanelSize }); - }); - forceRender(component); - const newTopPanelHeight = (newTopPanelSize / 100) * containerHeight; - expect(onTopPanelHeightChange).toHaveBeenCalledWith(newTopPanelHeight); - expectCorrectPanelSizes(component, containerHeight, newTopPanelHeight); - }); - - it('should maintain the height of the top panel and resize the main panel when the container height changes', () => { - const initialTopPanelHeight = 200; - const component = mountComponent({ initialTopPanelHeight }); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - const newContainerHeight = 2000; - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerHeight, width: 0 }); - forceRender(component); - expectCorrectPanelSizes(component, newContainerHeight, initialTopPanelHeight); - }); - - it('should resize the top panel once the main panel is at its minimum height', () => { - const initialTopPanelHeight = 500; - const minTopPanelHeight = 100; - const minMainPanelHeight = 100; - const component = mountComponent({ - initialTopPanelHeight, - minTopPanelHeight, - minMainPanelHeight, - }); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - const newContainerHeight = 400; - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerHeight, width: 0 }); - forceRender(component); - expectCorrectPanelSizes(component, newContainerHeight, newContainerHeight - minMainPanelHeight); - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: containerHeight, width: 0 }); - forceRender(component); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - }); - - it('should maintain the minimum heights of both panels when the container is too small to fit them', () => { - const initialTopPanelHeight = 500; - const minTopPanelHeight = 100; - const minMainPanelHeight = 150; - const component = mountComponent({ - initialTopPanelHeight, - minTopPanelHeight, - minMainPanelHeight, - }); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - const newContainerHeight = 200; - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: newContainerHeight, width: 0 }); - forceRender(component); - expect( - component.find('[data-test-subj="unifiedHistogramResizablePanelTop"]').at(0).prop('size') - ).toBe((minTopPanelHeight / newContainerHeight) * 100); - expect( - component.find('[data-test-subj="unifiedHistogramResizablePanelMain"]').at(0).prop('size') - ).toBe((minMainPanelHeight / newContainerHeight) * 100); - jest.spyOn(eui, 'useResizeObserver').mockReturnValue({ height: containerHeight, width: 0 }); - forceRender(component); - expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight); - }); - - it('should blur the resize button after a resize', async () => { - const attachTo = document.createElement('div'); - document.body.appendChild(attachTo); - const component = mountComponent({ attachTo }); - const getContainer = () => - component.find('[data-test-subj="unifiedHistogramResizableContainer"]').at(0); - const resizeButton = component.find('button[data-test-subj="unifiedHistogramResizableButton"]'); - act(() => { - const onResizeStart = getContainer().prop('onResizeStart') as Function; - onResizeStart('pointer'); - }); - (resizeButton.getDOMNode() as HTMLElement).focus(); - forceRender(component); - act(() => { - const onResizeEnd = getContainer().prop('onResizeEnd') as Function; - onResizeEnd(); - }); - expect(resizeButton.getDOMNode()).toHaveFocus(); - await waitFor(() => { - expect(resizeButton.getDOMNode()).not.toHaveFocus(); - }); - }); -}); diff --git a/src/plugins/unified_histogram/public/panels/panels_resizable.tsx b/src/plugins/unified_histogram/public/panels/panels_resizable.tsx deleted file mode 100644 index 9f8fd5338a38fe..00000000000000 --- a/src/plugins/unified_histogram/public/panels/panels_resizable.tsx +++ /dev/null @@ -1,197 +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 { EuiResizableContainer, useGeneratedHtmlId, useResizeObserver } from '@elastic/eui'; -import type { ResizeTrigger } from '@elastic/eui/src/components/resizable_container/types'; -import { css } from '@emotion/react'; -import { isEqual, round } from 'lodash'; -import type { ReactElement, RefObject } from 'react'; -import React, { useCallback, useEffect, useState } from 'react'; - -const percentToPixels = (containerHeight: number, percentage: number) => - Math.round(containerHeight * (percentage / 100)); - -const pixelsToPercent = (containerHeight: number, pixels: number) => - (pixels / containerHeight) * 100; - -export const PanelsResizable = ({ - className, - resizeRef, - topPanelHeight, - minTopPanelHeight, - minMainPanelHeight, - topPanel, - mainPanel, - onTopPanelHeightChange, -}: { - className?: string; - resizeRef: RefObject; - topPanelHeight: number; - minTopPanelHeight: number; - minMainPanelHeight: number; - topPanel: ReactElement; - mainPanel: ReactElement; - onTopPanelHeightChange?: (topPanelHeight: number) => void; -}) => { - const topPanelId = useGeneratedHtmlId({ prefix: 'topPanel' }); - const { height: containerHeight } = useResizeObserver(resizeRef.current); - const [panelSizes, setPanelSizes] = useState({ topPanelSize: 0, mainPanelSize: 0 }); - - // EuiResizableContainer doesn't work properly when used with react-reverse-portal and - // will cancel the resize. To work around this we keep track of when resizes start and - // end to toggle the rendering of a transparent overlay which prevents the cancellation. - // EUI issue: https://github.com/elastic/eui/issues/6199 - const [resizeWithPortalsHackIsResizing, setResizeWithPortalsHackIsResizing] = useState(false); - const enableResizeWithPortalsHack = useCallback( - () => setResizeWithPortalsHackIsResizing(true), - [] - ); - const disableResizeWithPortalsHack = useCallback( - () => setResizeWithPortalsHackIsResizing(false), - [] - ); - const resizeWithPortalsHackButtonCss = css` - z-index: 3; - `; - const resizeWithPortalsHackOverlayCss = css` - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 2; - `; - - // We convert the top panel height from a percentage of the container height - // to a pixel value and emit the change to the parent component. We also convert - // the pixel value back to a percentage before updating the panel sizes to avoid - // rounding issues with the isEqual check in the effect below. - const onPanelSizeChange = useCallback( - ({ [topPanelId]: topPanelSize }: { [key: string]: number }) => { - const newTopPanelHeight = percentToPixels(containerHeight, topPanelSize); - const newTopPanelSize = pixelsToPercent(containerHeight, newTopPanelHeight); - - setPanelSizes({ - topPanelSize: round(newTopPanelSize, 4), - mainPanelSize: round(100 - newTopPanelSize, 4), - }); - - onTopPanelHeightChange?.(newTopPanelHeight); - }, - [containerHeight, onTopPanelHeightChange, topPanelId] - ); - - // This effect will update the panel sizes based on the top panel height whenever - // it or the container height changes. This allows us to keep the height of the - // top panel fixed when the window is resized. - useEffect(() => { - if (!containerHeight) { - return; - } - - let topPanelSize: number; - let mainPanelSize: number; - - // If the container height is less than the minimum main content height - // plus the current top panel height, then we need to make some adjustments. - if (containerHeight < minMainPanelHeight + topPanelHeight) { - const newTopPanelHeight = containerHeight - minMainPanelHeight; - - // Try to make the top panel height fit within the container, but if it - // doesn't then just use the minimum heights. - if (newTopPanelHeight < minTopPanelHeight) { - topPanelSize = pixelsToPercent(containerHeight, minTopPanelHeight); - mainPanelSize = pixelsToPercent(containerHeight, minMainPanelHeight); - } else { - topPanelSize = pixelsToPercent(containerHeight, newTopPanelHeight); - mainPanelSize = 100 - topPanelSize; - } - } else { - topPanelSize = pixelsToPercent(containerHeight, topPanelHeight); - mainPanelSize = 100 - topPanelSize; - } - - const newPanelSizes = { - topPanelSize: round(topPanelSize, 4), - mainPanelSize: round(mainPanelSize, 4), - }; - - // Skip updating the panel sizes if they haven't changed - // since onPanelSizeChange will also trigger this effect. - if (!isEqual(panelSizes, newPanelSizes)) { - setPanelSizes(newPanelSizes); - } - }, [containerHeight, minMainPanelHeight, minTopPanelHeight, panelSizes, topPanelHeight]); - - const onResizeStart = useCallback( - (trigger: ResizeTrigger) => { - if (trigger !== 'pointer') { - return; - } - - enableResizeWithPortalsHack(); - }, - [enableResizeWithPortalsHack] - ); - - const onResizeEnd = useCallback(() => { - if (!resizeWithPortalsHackIsResizing) { - return; - } - - // We don't want the resize button to retain focus after the resize is complete, - // but EuiResizableContainer will force focus it onClick. To work around this we - // use setTimeout to wait until after onClick has been called before blurring. - if (document.activeElement instanceof HTMLElement) { - const button = document.activeElement; - setTimeout(() => { - button.blur(); - }); - } - - disableResizeWithPortalsHack(); - }, [disableResizeWithPortalsHack, resizeWithPortalsHackIsResizing]); - - return ( - - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - {topPanel} - - - - {mainPanel} - - {resizeWithPortalsHackIsResizing ?
: <>} - - )} - - ); -}; diff --git a/src/plugins/unified_histogram/tsconfig.json b/src/plugins/unified_histogram/tsconfig.json index 0dc5b1fe9d52ba..b8337379679c3d 100644 --- a/src/plugins/unified_histogram/tsconfig.json +++ b/src/plugins/unified_histogram/tsconfig.json @@ -25,6 +25,7 @@ "@kbn/kibana-utils-plugin", "@kbn/visualizations-plugin", "@kbn/discover-utils", + "@kbn/resizable-layout", ], "exclude": [ "target/**/*", diff --git a/test/functional/apps/discover/group1/_discover.ts b/test/functional/apps/discover/group1/_discover.ts index 286a30a6bb2274..2933dd02f15259 100644 --- a/test/functional/apps/discover/group1/_discover.ts +++ b/test/functional/apps/discover/group1/_discover.ts @@ -31,8 +31,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { defaultIndex: 'logstash-*', }; - // FLAKY: https://github.com/elastic/kibana/issues/146223 - describe.skip('discover test', function describeIndexTests() { + describe('discover test', function describeIndexTests() { before(async function () { log.debug('load kibana index with default index pattern'); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); @@ -112,7 +111,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); - it('should show correct initial chart interval of Auto', async function () { + // FLAKY: https://github.com/elastic/kibana/issues/146223 + it.skip('should show correct initial chart interval of Auto', async function () { await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.discover.waitUntilSearchingHasFinished(); const actualInterval = await PageObjects.discover.getChartInterval(); @@ -127,6 +127,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should reload the saved search with persisted query to show the initial hit count', async function () { + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.discover.waitUntilSearchingHasFinished(); // apply query some changes await queryBar.setQuery('test'); await queryBar.submitQuery(); @@ -298,10 +300,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('resizable layout panels', () => { - it('should allow resizing the layout panels', async () => { + it('should allow resizing the histogram layout panels', async () => { const resizeDistance = 100; - const topPanel = await testSubjects.find('unifiedHistogramResizablePanelTop'); - const mainPanel = await testSubjects.find('unifiedHistogramResizablePanelMain'); + const topPanel = await testSubjects.find('unifiedHistogramResizablePanelFixed'); + const mainPanel = await testSubjects.find('unifiedHistogramResizablePanelFlex'); const resizeButton = await testSubjects.find('unifiedHistogramResizableButton'); const topPanelSize = (await topPanel.getPosition()).height; const mainPanelSize = (await mainPanel.getPosition()).height; @@ -314,6 +316,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(newTopPanelSize).to.be(topPanelSize + resizeDistance); expect(newMainPanelSize).to.be(mainPanelSize - resizeDistance); }); + + it('should allow resizing the sidebar layout panels', async () => { + const resizeDistance = 100; + const leftPanel = await testSubjects.find('discoverLayoutResizablePanelFixed'); + const mainPanel = await testSubjects.find('discoverLayoutResizablePanelFlex'); + const resizeButton = await testSubjects.find('discoverLayoutResizableButton'); + const leftPanelSize = (await leftPanel.getPosition()).width; + const mainPanelSize = (await mainPanel.getPosition()).width; + await browser.dragAndDrop( + { location: resizeButton }, + { location: { x: resizeDistance, y: 0 } } + ); + const newLeftPanelSize = (await leftPanel.getPosition()).width; + const newMainPanelSize = (await mainPanel.getPosition()).width; + expect(newLeftPanelSize).to.be(leftPanelSize + resizeDistance); + expect(newMainPanelSize).to.be(mainPanelSize - resizeDistance); + }); }); describe('URL state', () => { diff --git a/test/functional/apps/management/data_views/_scripted_fields.ts b/test/functional/apps/management/data_views/_scripted_fields.ts index 5bbbc85488d286..e49eb11310504b 100644 --- a/test/functional/apps/management/data_views/_scripted_fields.ts +++ b/test/functional/apps/management/data_views/_scripted_fields.ts @@ -155,7 +155,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should see scripted field value in Discover', async function () { await PageObjects.common.navigateToApp('discover'); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName); }); @@ -261,7 +260,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should see scripted field value in Discover', async function () { await PageObjects.common.navigateToApp('discover'); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); @@ -366,7 +364,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should see scripted field value in Discover', async function () { await PageObjects.common.navigateToApp('discover'); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); @@ -464,7 +461,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should see scripted field value in Discover', async function () { await PageObjects.common.navigateToApp('discover'); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); diff --git a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts b/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts index a2fbcb43cfe5b9..0ca095811c0b44 100644 --- a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts +++ b/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts @@ -143,7 +143,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName); }); @@ -233,7 +232,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); @@ -322,7 +320,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); @@ -412,7 +409,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); }); diff --git a/tsconfig.base.json b/tsconfig.base.json index b43c2b3a918470..030b5c9bbed4cc 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1156,6 +1156,10 @@ "@kbn/reporting-example-plugin/*": ["x-pack/examples/reporting_example/*"], "@kbn/reporting-plugin": ["x-pack/plugins/reporting"], "@kbn/reporting-plugin/*": ["x-pack/plugins/reporting/*"], + "@kbn/resizable-layout": ["packages/kbn-resizable-layout"], + "@kbn/resizable-layout/*": ["packages/kbn-resizable-layout/*"], + "@kbn/resizable-layout-examples-plugin": ["examples/resizable_layout_examples"], + "@kbn/resizable-layout-examples-plugin/*": ["examples/resizable_layout_examples/*"], "@kbn/resolver-test-plugin": ["x-pack/test/plugin_functional/plugins/resolver_test"], "@kbn/resolver-test-plugin/*": ["x-pack/test/plugin_functional/plugins/resolver_test/*"], "@kbn/response-stream-plugin": ["examples/response_stream"], diff --git a/yarn.lock b/yarn.lock index 861e3d293a17ea..41769ceb9a6efc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5255,6 +5255,14 @@ version "0.0.0" uid "" +"@kbn/resizable-layout-examples-plugin@link:examples/resizable_layout_examples": + version "0.0.0" + uid "" + +"@kbn/resizable-layout@link:packages/kbn-resizable-layout": + version "0.0.0" + uid "" + "@kbn/resolver-test-plugin@link:x-pack/test/plugin_functional/plugins/resolver_test": version "0.0.0" uid "" From 8e6101e752d38dfdaf773e62e14141772c8ca95c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 28 Sep 2023 00:43:37 -0400 Subject: [PATCH 21/22] [api-docs] 2023-09-28 Daily api_docs build (#167461) Generated by https://buildkite.com/elastic/kibana-api-docs-daily/builds/474 --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.devdocs.json | 16 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.devdocs.json | 17 +- api_docs/alerting.mdx | 4 +- api_docs/apm.mdx | 2 +- api_docs/apm_data_access.mdx | 2 +- api_docs/asset_manager.devdocs.json | 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.devdocs.json | 80 ----- api_docs/data.mdx | 2 +- api_docs/data_query.mdx | 2 +- api_docs/data_search.mdx | 2 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.devdocs.json | 40 --- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 6 +- api_docs/deprecations_by_plugin.mdx | 6 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/ecs_data_quality_dashboard.mdx | 2 +- api_docs/elastic_assistant.mdx | 2 +- api_docs/embeddable.devdocs.json | 14 + api_docs/embeddable.mdx | 4 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_annotation_listing.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/exploratory_view.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/files_management.mdx | 2 +- api_docs/fleet.mdx | 2 +- api_docs/global_search.mdx | 2 +- api_docs/guided_onboarding.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/image_embeddable.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.devdocs.json | 14 - api_docs/infra.mdx | 4 +- 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.devdocs.json | 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.devdocs.json | 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.devdocs.json | 66 +++- api_docs/kbn_core_chrome_browser.mdx | 4 +- 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 | 18 +- 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 +- ...core_saved_objects_api_server.devdocs.json | 40 --- .../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 +- ...kbn_core_saved_objects_common.devdocs.json | 12 + 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 +- ...kbn_core_saved_objects_server.devdocs.json | 40 --- 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 +- .../kbn_default_nav_analytics.devdocs.json | 2 +- api_docs/kbn_default_nav_analytics.mdx | 2 +- .../kbn_default_nav_devtools.devdocs.json | 2 +- api_docs/kbn_default_nav_devtools.mdx | 2 +- .../kbn_default_nav_management.devdocs.json | 2 +- api_docs/kbn_default_nav_management.mdx | 2 +- api_docs/kbn_default_nav_ml.devdocs.json | 2 +- api_docs/kbn_default_nav_ml.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_discover_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_dom_drag_drop.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_ecs.mdx | 2 +- api_docs/kbn_ecs_data_quality_dashboard.mdx | 2 +- api_docs/kbn_elastic_assistant.devdocs.json | 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.devdocs.json | 6 +- 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 +- ...bn_management_settings_components_form.mdx | 2 +- ...n_management_settings_field_definition.mdx | 2 +- api_docs/kbn_management_settings_ids.mdx | 2 +- ...n_management_settings_section_registry.mdx | 2 +- api_docs/kbn_management_settings_types.mdx | 2 +- .../kbn_management_settings_utilities.mdx | 2 +- api_docs/kbn_management_storybook_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_maps_vector_tile_utils.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_anomaly_utils.mdx | 2 +- api_docs/kbn_ml_category_validator.mdx | 2 +- api_docs/kbn_ml_chi2test.devdocs.json | 269 +++++++++++++++ api_docs/kbn_ml_chi2test.mdx | 36 ++ .../kbn_ml_data_frame_analytics_utils.mdx | 2 +- api_docs/kbn_ml_data_grid.mdx | 2 +- api_docs/kbn_ml_date_picker.devdocs.json | 22 +- api_docs/kbn_ml_date_picker.mdx | 4 +- api_docs/kbn_ml_date_utils.mdx | 2 +- api_docs/kbn_ml_error_utils.mdx | 2 +- api_docs/kbn_ml_in_memory_table.mdx | 2 +- api_docs/kbn_ml_is_defined.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_kibana_theme.mdx | 2 +- api_docs/kbn_ml_local_storage.mdx | 2 +- api_docs/kbn_ml_nested_property.mdx | 2 +- api_docs/kbn_ml_number_utils.mdx | 2 +- api_docs/kbn_ml_query_utils.mdx | 2 +- api_docs/kbn_ml_random_sampler_utils.mdx | 2 +- api_docs/kbn_ml_route_utils.mdx | 2 +- api_docs/kbn_ml_runtime_field_utils.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_ml_trained_models_utils.mdx | 2 +- api_docs/kbn_ml_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.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- api_docs/kbn_osquery_io_ts_types.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_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_resizable_layout.devdocs.json | 321 ++++++++++++++++++ api_docs/kbn_resizable_layout.mdx | 36 ++ api_docs/kbn_rison.mdx | 2 +- api_docs/kbn_rrule.mdx | 2 +- api_docs/kbn_rule_data_utils.devdocs.json | 17 +- api_docs/kbn_rule_data_utils.mdx | 4 +- 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 +- 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 +- ...n_shared_ux_chrome_navigation.devdocs.json | 16 + api_docs/kbn_shared_ux_chrome_navigation.mdx | 4 +- 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 +- .../kbn_shared_ux_markdown_mocks.devdocs.json | 27 +- api_docs/kbn_shared_ux_markdown_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_prompt_not_found.mdx | 2 +- api_docs/kbn_shared_ux_router.mdx | 2 +- api_docs/kbn_shared_ux_router_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_config.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_slo_schema.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_subscription_tracking.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_test_subj_selector.mdx | 2 +- api_docs/kbn_text_based_editor.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_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.devdocs.json | 15 + api_docs/kbn_unified_field_list.mdx | 4 +- api_docs/kbn_url_state.mdx | 2 +- api_docs/kbn_use_tracked_promise.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_visualization_ui_components.mdx | 2 +- api_docs/kbn_xstate_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.devdocs.json | 112 +++++- api_docs/lens.mdx | 4 +- 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 | 60 ++-- 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 +- api_docs/observability_a_i_assistant.mdx | 2 +- api_docs/observability_log_explorer.mdx | 2 +- api_docs/observability_onboarding.mdx | 2 +- api_docs/observability_shared.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/painless_lab.mdx | 2 +- api_docs/plugin_directory.mdx | 32 +- api_docs/presentation_util.mdx | 2 +- api_docs/profiling.mdx | 2 +- api_docs/profiling_data_access.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- api_docs/saved_objects_finder.mdx | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.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.devdocs.json | 11 + api_docs/triggers_actions_ui.mdx | 4 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_doc_viewer.mdx | 2 +- api_docs/unified_histogram.devdocs.json | 66 +++- api_docs/unified_histogram.mdx | 4 +- 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 +- 625 files changed, 1682 insertions(+), 954 deletions(-) create mode 100644 api_docs/kbn_ml_chi2test.devdocs.json create mode 100644 api_docs/kbn_ml_chi2test.mdx create mode 100644 api_docs/kbn_resizable_layout.devdocs.json create mode 100644 api_docs/kbn_resizable_layout.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 12b91c8371bb1f..9a116bd9aa00b6 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-27 +date: 2023-09-28 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 e3214171faf714..dbf9c0fc8cec37 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index 9ac02672162775..3b8d80304d1d53 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -776,10 +776,10 @@ }, { "parentPluginId": "aiops", - "id": "def-public.ChangePointDetectionAppStateProps.isServerless", + "id": "def-public.ChangePointDetectionAppStateProps.showFrozenDataTierChoice", "type": "CompoundType", "tags": [], - "label": "isServerless", + "label": "showFrozenDataTierChoice", "description": [ "Optional flag to indicate whether kibana is running in serverless" ], @@ -875,10 +875,10 @@ }, { "parentPluginId": "aiops", - "id": "def-public.LogCategorizationAppStateProps.isServerless", + "id": "def-public.LogCategorizationAppStateProps.showFrozenDataTierChoice", "type": "CompoundType", "tags": [], - "label": "isServerless", + "label": "showFrozenDataTierChoice", "description": [ "Optional flag to indicate whether kibana is running in serverless" ], @@ -990,10 +990,10 @@ }, { "parentPluginId": "aiops", - "id": "def-public.LogRateAnalysisAppStateProps.isServerless", + "id": "def-public.LogRateAnalysisAppStateProps.showFrozenDataTierChoice", "type": "CompoundType", "tags": [], - "label": "isServerless", + "label": "showFrozenDataTierChoice", "description": [ "Optional flag to indicate whether kibana is running in serverless" ], @@ -1237,10 +1237,10 @@ }, { "parentPluginId": "aiops", - "id": "def-public.LogRateAnalysisContentWrapperProps.isServerless", + "id": "def-public.LogRateAnalysisContentWrapperProps.showFrozenDataTierChoice", "type": "CompoundType", "tags": [], - "label": "isServerless", + "label": "showFrozenDataTierChoice", "description": [ "Optional flag to indicate whether kibana is running in serverless" ], diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 2e4a76b9141afa..3eb68f5e67a564 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index da3be79e6776e3..4a97328c5bbd94 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -4920,11 +4920,7 @@ "section": "def-common.RuleTypeParams", "text": "RuleTypeParams" }, - ">, \"id\" | \"snoozeSchedule\">; version?: string | undefined; }) => Promise; unmuteAll: (options: { id: string; }) => Promise; muteInstance: (options: ", - "MuteOptions", - ") => Promise; unmuteInstance: (options: ", - "MuteOptions", - ") => Promise; runSoon: (options: { id: string; }) => Promise; listRuleTypes: () => Promise, \"id\" | \"snoozeSchedule\">; version?: string | undefined; }) => Promise; unmuteAll: (options: { id: string; }) => Promise; muteInstance: (options: Readonly<{} & { alertId: string; alertInstanceId: string; }>) => Promise; unmuteInstance: (options: Readonly<{} & { alertId: string; alertInstanceId: string; }>) => Promise; runSoon: (options: { id: string; }) => Promise; listRuleTypes: () => Promise>; getSpaceId: () => string | undefined; getAuthorization: () => ", { @@ -6254,6 +6250,17 @@ "path": "x-pack/plugins/alerting/common/alert_summary.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "alerting", + "id": "def-common.AlertStatus.tracked", + "type": "boolean", + "tags": [], + "label": "tracked", + "description": [], + "path": "x-pack/plugins/alerting/common/alert_summary.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 7592b9d71d70d1..a9cfdd9c6283c8 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 772 | 1 | 741 | 51 | +| 773 | 1 | 742 | 50 | ## Client diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 2e853b562576ed..4762b1407b25ab 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-27 +date: 2023-09-28 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 3c7d9c1c1c4ff3..1e5c28a1e94d04 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.devdocs.json b/api_docs/asset_manager.devdocs.json index 7f2baa50411c4a..5f7f45af9f998d 100644 --- a/api_docs/asset_manager.devdocs.json +++ b/api_docs/asset_manager.devdocs.json @@ -22,7 +22,7 @@ "label": "AssetManagerConfig", "description": [], "signature": [ - "{ readonly alphaEnabled?: boolean | undefined; readonly sourceIndices: Readonly<{} & { metrics: string; logs: string; }>; readonly lockedSource: \"assets\" | \"signals\"; }" + "{ readonly alphaEnabled?: boolean | undefined; readonly sourceIndices: Readonly<{} & { logs: string; }>; readonly lockedSource: \"assets\" | \"signals\"; }" ], "path": "x-pack/plugins/asset_manager/server/types.ts", "deprecated": false, diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index e267a022137341..ddf0cc20472fe4 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-27 +date: 2023-09-28 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 00cd00b3d8b7ca..b2669d7582a7b0 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-27 +date: 2023-09-28 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 b76a791d578649..1fae7087215880 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-27 +date: 2023-09-28 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 973968148c9e28..17162885d6c6fb 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-27 +date: 2023-09-28 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 40e94f9c574a07..ee01032ea5bbb4 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-27 +date: 2023-09-28 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 68cb43f4cdcf82..d8f4058a7693c6 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-27 +date: 2023-09-28 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 723d476304190a..b0df4aec4917cd 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-27 +date: 2023-09-28 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 10ea75521a594c..59f6308448b287 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-27 +date: 2023-09-28 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 b144fc2eccc4c3..1a10061b30cb7e 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-27 +date: 2023-09-28 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 6582ca6dafac6f..8105ffe2731a9a 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-27 +date: 2023-09-28 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 039ccab8b05b7a..ed4603e068a474 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-27 +date: 2023-09-28 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 297e9465c0dbc3..9254d1947b0824 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-27 +date: 2023-09-28 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 e0f9d6a8153af6..f566e653ba31b2 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-27 +date: 2023-09-28 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 7f2fad0fdbbca9..81e8162e0c1844 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-27 +date: 2023-09-28 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 9bd36e06920279..ed9e7f7c42fffc 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-27 +date: 2023-09-28 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 9ffbb619fc035e..adb1072427e54b 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-27 +date: 2023-09-28 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 bde1fee9211b44..3c92e9bf5fb051 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-27 +date: 2023-09-28 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 8e0d9fe3a3f8f3..bc9e62b6ea68f6 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-27 +date: 2023-09-28 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 6a9123356ad835..85c05d0182f96b 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 372461cf97e4e0..c7c415ce2a07d8 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -8857,46 +8857,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" @@ -27782,46 +27742,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/data.mdx b/api_docs/data.mdx index c821f234780e62..76c97d8b1bf9f0 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-27 +date: 2023-09-28 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 84ff30a00dfaa6..4a3052e69dacbb 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-27 +date: 2023-09-28 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 36a9790b3c52ca..55c7a1cd375480 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-27 +date: 2023-09-28 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 9faca8b31e54fe..523efeb3c400be 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-27 +date: 2023-09-28 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 8bcfd4d30daadc..34b59f7b16539a 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-27 +date: 2023-09-28 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 3eb4fe4a74a2f5..c82cf17f021848 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index d975cfb1c88261..baaf0d95bec9c6 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -24390,46 +24390,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 5c7c7d91590af3..ae7cee83fdaf7c 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-27 +date: 2023-09-28 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 b26b5722348b63..57fc66f96769ee 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-27 +date: 2023-09-28 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 02d5eca6f24b77..4bf60fbe5107a2 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -32,8 +32,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | | | alerting, discover, securitySolution | - | -| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, home, fleet, osquery, securitySolution, @kbn/core-saved-objects-browser-mocks, graph, lists, alerting | - | -| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, home, fleet, osquery, securitySolution, @kbn/core-saved-objects-browser-mocks, graph, lists, alerting | - | +| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, fleet, osquery, securitySolution, @kbn/core-saved-objects-browser-mocks, graph, lists, alerting | - | +| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, fleet, osquery, securitySolution, @kbn/core-saved-objects-browser-mocks, graph, lists, alerting | - | | | alerting, discover, securitySolution | - | | | securitySolution | - | | | inspector, data, licensing, security, savedObjects, runtimeFields, indexManagement, dataViewEditor, unifiedSearch, embeddable, visualizations, controls, dashboard, savedObjectsTagging, dataViewFieldEditor, lens, triggersActionsUi, cases, observabilityShared, telemetry, advancedSettings, maps, exploratoryView, fleet, observability, banners, reporting, timelines, cloudSecurityPosture, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, uptime, cloudLinks, console, dataViewManagement, eventAnnotationListing, filesManagement, uiActions, visTypeVislib | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index ae4b936e620544..70748cc0ec64bb 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -963,8 +963,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [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 | - | | | [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) | - | @@ -1084,7 +1082,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock) | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference)+ 48 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/common/embeddable_factory/index.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference)+ 51 more | - | | | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/server/saved_objects.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 33493d3e7c5fe2..d054cf4f50421d 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index e164309adfc176..681d6ea6ee0f89 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-27 +date: 2023-09-28 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 502e441a59e125..7e4613c8b526e5 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-27 +date: 2023-09-28 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 0707de8d80f73b..2662254790013f 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-27 +date: 2023-09-28 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 a43391dfdd6050..2952cedf21aacc 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-27 +date: 2023-09-28 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 9516628c66de86..b44b2760277afd 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index 10b115cf089323..7a9b4ecfe0f4b2 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -7236,6 +7236,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "embeddable", + "id": "def-public.EmbeddableOutput.inlineEditable", + "type": "CompoundType", + "tags": [], + "label": "inlineEditable", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "embeddable", "id": "def-public.EmbeddableOutput.editableWithExplicitInput", diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index b967fd65517081..389b472c148823 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 535 | 1 | 435 | 7 | +| 536 | 1 | 436 | 7 | ## Client diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index fe5578c5872b1b..802133f6f3c4d4 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-27 +date: 2023-09-28 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 d8bd4252fc1056..1d63bf970b4252 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index a1feaa96c7262a..e591dad53c18e8 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index e1de23125551e4..96da6af418e4ab 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-27 +date: 2023-09-28 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 8612928b4d8973..dc4606d5d2d4fe 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-27 +date: 2023-09-28 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 86825377b6cc1d..0707c1b1383a73 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-27 +date: 2023-09-28 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 d262a795e9dfcb..e2af544c6e6b5b 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-27 +date: 2023-09-28 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 3534c64c75114b..2ae6be49ddd0fa 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-27 +date: 2023-09-28 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 d8f8ce4777c0fb..1bcc90f528d1b2 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-27 +date: 2023-09-28 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 9c8be61eab7e35..2ce1a615ca238f 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-27 +date: 2023-09-28 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 abbc24ecd3dc18..df39e25be4c53d 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-27 +date: 2023-09-28 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 4d7e8563ded553..75d74beedbbeef 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-27 +date: 2023-09-28 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 a9676a6672dcb2..b723258dfddb64 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-27 +date: 2023-09-28 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 cb4d694a4799f3..68a4290d60a09c 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-27 +date: 2023-09-28 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 4fb5d3de6ab64f..a2b32a9605615d 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-27 +date: 2023-09-28 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 c0cc747d573610..782c09bf5dfa0d 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-27 +date: 2023-09-28 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 32b4ba7b8e1be1..8a8abcb0986f58 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-27 +date: 2023-09-28 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 4072d1d65a1713..885a5bc817153b 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-27 +date: 2023-09-28 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 0241361493e489..333ac75323a6d5 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-27 +date: 2023-09-28 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 427994f18cc4f1..40ae51a93fefdd 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-27 +date: 2023-09-28 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 b625cb5fea8da5..6e295133add2be 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-27 +date: 2023-09-28 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 3cb09730248db8..7c1f8bc7e457ad 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-27 +date: 2023-09-28 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 d319a8e453d2f6..5d59732350fe7d 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-27 +date: 2023-09-28 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 acea1c1b4dc23f..4e9a554d0015ef 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-27 +date: 2023-09-28 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 c1306492e6e9c9..be3cfb4b97debd 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-27 +date: 2023-09-28 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 52a957d804bb40..5086e4beec0e0b 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-27 +date: 2023-09-28 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 18046b81816fe4..8f52135ba4dd6b 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 2581af68b9cb5f..6cf756020fa683 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 34fa9db21d7361..456dac06309b8e 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-27 +date: 2023-09-28 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 b9ada15f3ffcf0..8bfce4cd57e0e2 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-27 +date: 2023-09-28 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 bf2a070742443d..e67d44b43c7b45 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-27 +date: 2023-09-28 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 4029b9f116b8c2..42ba88f74ce768 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-27 +date: 2023-09-28 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 de6dc19aaaae61..bd719fbceab660 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-27 +date: 2023-09-28 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 7de9acbd421237..a481bc52815a33 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.devdocs.json b/api_docs/infra.devdocs.json index 2e4e16322dc435..96d9281438a025 100644 --- a/api_docs/infra.devdocs.json +++ b/api_docs/infra.devdocs.json @@ -468,20 +468,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "infra", - "id": "def-server.InfraConfig.logs", - "type": "Object", - "tags": [], - "label": "logs", - "description": [], - "signature": [ - "{ app_target: \"discover\" | \"logs-ui\"; }" - ], - "path": "x-pack/plugins/infra/common/plugin_config_types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "infra", "id": "def-server.InfraConfig.sources", diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 76744edfef6fa8..5bfc662f9e4b70 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/inf | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 42 | 0 | 39 | 11 | +| 41 | 0 | 38 | 11 | ## Client diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 9825df29f4a7f9..e111316a051c02 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-27 +date: 2023-09-28 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 9534753171845e..cc1e3742faa202 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-27 +date: 2023-09-28 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 ffa2697b5764f8..077667c0faf96a 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-27 +date: 2023-09-28 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 3e9add987aa659..5c69c8b12cbbef 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-27 +date: 2023-09-28 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 5c24f9e78cb6fd..c757fd7c1582a5 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-27 +date: 2023-09-28 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 d52e7cc4fa8cdb..a397098b06097f 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-27 +date: 2023-09-28 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 69e289a1fd58b5..a524f5f57697f9 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-27 +date: 2023-09-28 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 4ce8b147a1c2c8..ee877bbdcf4bf3 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_alerts_ui_shared.devdocs.json index a63af81c308488..d9d2bf448a8ebe 100644 --- a/api_docs/kbn_alerts_ui_shared.devdocs.json +++ b/api_docs/kbn_alerts_ui_shared.devdocs.json @@ -168,7 +168,7 @@ "label": "alertStatus", "description": [], "signature": [ - "\"recovered\" | \"active\"" + "\"recovered\" | \"active\" | \"untracked\"" ], "path": "packages/kbn-alerts-ui-shared/src/alert_lifecycle_status_badge/index.tsx", "deprecated": false, diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 9b493b17c6f902..d97e765f4470d7 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-27 +date: 2023-09-28 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 b21b2bccbf7f7f..2bdd1ea5a93f58 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-27 +date: 2023-09-28 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 f93c4814632a74..3f6ff18a4f42f7 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-27 +date: 2023-09-28 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 f0072b2e611b8f..4803378aa63a07 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-27 +date: 2023-09-28 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 bda4aa4744c45f..34dc08a375b810 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-27 +date: 2023-09-28 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 d6f992237079ec..fc0e5978ed7435 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-27 +date: 2023-09-28 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 77ddc29edf664a..ede4f2872b3cfe 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-27 +date: 2023-09-28 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 e0560f560a3a00..7efddd2313255a 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-27 +date: 2023-09-28 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 5fafe6c839ebf9..dd6617c10f1da9 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-27 +date: 2023-09-28 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 8952dace68b2f0..19c84f38c9be14 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-27 +date: 2023-09-28 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 06014e04591151..cc124e0c5ecbc7 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-27 +date: 2023-09-28 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 90a8fed671909d..a80ea0d589ab46 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-27 +date: 2023-09-28 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 f7c71f7bb69523..e96e1040a5cd67 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-27 +date: 2023-09-28 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 460e14f064547b..d9132b2a63e0f5 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-27 +date: 2023-09-28 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 eb1ccf888893fe..2edf70d5494d10 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-27 +date: 2023-09-28 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 34646553e760d6..b5c46e686c2dd3 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-27 +date: 2023-09-28 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 8347d9d58f6457..284f86b7ebc35c 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-27 +date: 2023-09-28 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 b0cbb5ea164a51..f7fb52a4efdaf9 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-27 +date: 2023-09-28 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 f36300aedeec99..9dec5dcb660495 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-27 +date: 2023-09-28 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 e7320e039faffb..0586b9f3d1864b 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-27 +date: 2023-09-28 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 e4e9fcfe8e60ed..5b6983d6155c80 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-27 +date: 2023-09-28 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 58edce24c43e29..3b19c755cd8956 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-27 +date: 2023-09-28 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 080999aa9e01ab..dc746f3c840d75 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_coloring.devdocs.json index e8c0cba7b4c2c7..75bd30fc6e9e4c 100644 --- a/api_docs/kbn_coloring.devdocs.json +++ b/api_docs/kbn_coloring.devdocs.json @@ -1715,7 +1715,7 @@ "label": "type", "description": [], "signature": [ - "\"system_palette\" | \"palette\"" + "\"palette\" | \"system_palette\"" ], "path": "packages/kbn-coloring/src/palettes/types.ts", "deprecated": false, diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index b960b02b89b2d6..bdd3b49c0565bc 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-27 +date: 2023-09-28 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 e110d29f3a44fc..922a04674ff803 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-27 +date: 2023-09-28 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 02a6840e68f62c..592bf9ea4897f6 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-27 +date: 2023-09-28 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 038758b00f6f8e..97be862ab5a261 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-27 +date: 2023-09-28 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 709b7ce69ee92f..7cb613c139af13 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-27 +date: 2023-09-28 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 2cc9e3616b0df4..1890f2283fe092 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-27 +date: 2023-09-28 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 9267f6416b0fc7..bb796b11a5873c 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-27 +date: 2023-09-28 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 7ee1c9185b7fc8..9251b84da18a44 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-27 +date: 2023-09-28 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 10d45333c71bdb..d4cebb9c0bf3e6 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-27 +date: 2023-09-28 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 64a880c014f5de..d4533e8a3ca29c 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-27 +date: 2023-09-28 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 471633511b6ffd..79d0dacbb69765 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-27 +date: 2023-09-28 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 3e5e0a21393c83..36cb7ba1c0d919 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-27 +date: 2023-09-28 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 a7b0d9808c5c3b..6309657c046682 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-27 +date: 2023-09-28 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 11a1428b584919..0a3412e0460745 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-27 +date: 2023-09-28 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 df98a0e6edb273..26b1fba6429181 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-27 +date: 2023-09-28 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 e44c288783f903..8ebb8fb09de657 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-27 +date: 2023-09-28 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 e7fb15a08db41a..39aebf4ffbb820 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-27 +date: 2023-09-28 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 870ea5a8ed97cf..a6aacb26293bb4 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-27 +date: 2023-09-28 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 fc23b6d499462d..3a957dde7e4e90 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-27 +date: 2023-09-28 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 698ce102960b28..0d8658fe737d0e 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-27 +date: 2023-09-28 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 2ec632e026073a..478e7174601ec9 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-27 +date: 2023-09-28 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 eafbbbbfb7e2ce..ebc951ec9dd25c 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-27 +date: 2023-09-28 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 7725f53b100b2b..5180cf1af84165 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-27 +date: 2023-09-28 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 63d9aef51ba3e8..39f937c122185c 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-27 +date: 2023-09-28 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 bb56162d70dd68..31a1d4182c3c02 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-27 +date: 2023-09-28 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 a515fcb18dff80..5a19bc8be74a2d 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-27 +date: 2023-09-28 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 2857bb8d30e304..b71d5a4556622a 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-27 +date: 2023-09-28 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 39fa8b6558162b..a1ccb5925ab909 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-27 +date: 2023-09-28 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 da8e0297172b9e..c4cf94e48060b1 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-27 +date: 2023-09-28 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 8ab9f727a74624..b33b1085edc95b 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index f3b672baaa0cde..be4abc8f65299f 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -1555,6 +1555,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeProjectNavigationNode.isGroupTitle", + "type": "CompoundType", + "tags": [], + "label": "isGroupTitle", + "description": [ + "Optional flag to indicate if the node must be treated as a group title" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.ChromeProjectNavigationNode.children", @@ -1644,6 +1660,22 @@ "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.ChromeProjectNavigationNode.accordionProps", + "type": "Object", + "tags": [], + "label": "accordionProps", + "description": [], + "signature": [ + "Partial<", + "EuiAccordionProps", + "> | undefined" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2894,6 +2926,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.NodeDefinition.isGroupTitle", + "type": "CompoundType", + "tags": [], + "label": "isGroupTitle", + "description": [ + "\nOptional flag to indicate if the node must be treated as a group title.\nCan not be used with `children`" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-chrome-browser", "id": "def-common.NodeDefinition.children", @@ -2901,7 +2949,7 @@ "tags": [], "label": "children", "description": [ - "Optional children of the navigation node" + "Optional children of the navigation node. Can not be used with `isGroupTitle`" ], "signature": [ "NonEmptyArray<", @@ -2968,6 +3016,22 @@ "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-chrome-browser", + "id": "def-common.NodeDefinition.accordionProps", + "type": "Object", + "tags": [], + "label": "accordionProps", + "description": [], + "signature": [ + "Partial<", + "EuiAccordionProps", + "> | undefined" + ], + "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 264d9d1e80a2fb..1c7562d3c4a280 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.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 | |-------------------|-----------|------------------------|-----------------| -| 166 | 0 | 66 | 1 | +| 170 | 0 | 68 | 1 | ## Common diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index fcd4fcef062ce2..191515f6604d30 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-27 +date: 2023-09-28 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 88dd1c7a980932..88080e02a8983f 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-27 +date: 2023-09-28 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 fe62791fa9db9e..e2d167831114d8 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-27 +date: 2023-09-28 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 354d0881fb28d1..83e190da1dfe09 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-27 +date: 2023-09-28 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 439d757353ac95..23ff77dd3f0aca 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-27 +date: 2023-09-28 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 9f5687f9bf4ce1..b7726c6f599469 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-27 +date: 2023-09-28 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 dacf337e259b04..74ce0af21b3312 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-27 +date: 2023-09-28 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 25d2c6e975fe97..23ce5a0d344bf9 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-27 +date: 2023-09-28 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 44e4973ecac28f..0df2f3d89c5842 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-27 +date: 2023-09-28 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 bfb85d80fcaa4d..cb3c461f38ee06 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-27 +date: 2023-09-28 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 8b3fc320f82e9a..a1298bb3b7bf3d 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-27 +date: 2023-09-28 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 e514fb26d44fc0..fbc7d7c427c440 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-27 +date: 2023-09-28 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 27ee7dbdce221b..4424ce41db670b 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-27 +date: 2023-09-28 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 aa07083270e39c..ad60ef30c0fa53 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-27 +date: 2023-09-28 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 77a68b1e88b76a..53b91671f8f47a 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-27 +date: 2023-09-28 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 2a63618fc65aff..a56e3b4359ca2c 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-27 +date: 2023-09-28 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 07eb8e6b3c4cf2..f2c525376d8d4b 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-27 +date: 2023-09-28 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 df37f26a04f3e1..7d7c855cd3d137 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-27 +date: 2023-09-28 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 f7e305048e64fd..9efbbdcdfcbef1 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-27 +date: 2023-09-28 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 4762e16754e446..cb7d1b750f10db 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-27 +date: 2023-09-28 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 2d3e1a1a1bda7d..d8e3722069bf95 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-27 +date: 2023-09-28 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 e541b9fc65349f..0aa926b62157c8 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-27 +date: 2023-09-28 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 426ec9451ed874..7cce4be09ce73d 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-27 +date: 2023-09-28 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 7e9cd9324b3fff..de3db14329cbce 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-27 +date: 2023-09-28 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 3d41fa16a952bc..b6a1f74cddad6e 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-27 +date: 2023-09-28 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 3b75bd44a33a00..691311e977e5d7 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-27 +date: 2023-09-28 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 f3a5a6c0f144d5..80295a3083d693 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-27 +date: 2023-09-28 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 5c4357e365ddec..634cf3dcbd8bb6 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-27 +date: 2023-09-28 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 8cf0ca42347076..c593bbc12074df 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-27 +date: 2023-09-28 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 f89f870cf1a91e..fd7a220911d483 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-27 +date: 2023-09-28 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 b4666e03843bbb..86c30b168377b6 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-27 +date: 2023-09-28 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 bf811a0ebdb7c6..00cdaa00caea3b 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-27 +date: 2023-09-28 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 1fa83dadeb6ca2..10b8ec36f3db97 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-27 +date: 2023-09-28 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 4a58ea937f2e43..749548052ec4bb 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-27 +date: 2023-09-28 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 c2e252a36883c7..db3810525894e7 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-27 +date: 2023-09-28 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 bd8a13595ee89b..d23a328991d08b 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-27 +date: 2023-09-28 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 1e39e17f6eea13..4dea726a477fcc 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-27 +date: 2023-09-28 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 13b0341a011ebe..6a2de46613a312 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-27 +date: 2023-09-28 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 82980f92463038..a7a286980e44cf 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-27 +date: 2023-09-28 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 09122b26b22be8..12eb176db54fa0 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-27 +date: 2023-09-28 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 e752f460319b5f..5e02cb98942e74 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-27 +date: 2023-09-28 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 8a72477f0a7a39..2868840a5b79eb 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-27 +date: 2023-09-28 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 c4bd2938980f3f..2a8e5aa4f16743 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-27 +date: 2023-09-28 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 d954beadc3508f..873b5e1bc49c8d 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-27 +date: 2023-09-28 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 f9d6da194067d1..3b3ff461777e18 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-27 +date: 2023-09-28 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 6ee60c96f2ad2c..a075a2a2bd853d 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-27 +date: 2023-09-28 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 de8c19412e2bff..e57b8659b76430 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-27 +date: 2023-09-28 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 bba55956eb84e8..480bb9d8a76a7c 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -6043,7 +6043,7 @@ }, { "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/routes/mute_alert.ts" + "path": "x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts" }, { "plugin": "alerting", @@ -7133,14 +7133,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/enable_rule.test.ts" }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/routes/mute_alert.test.ts" - }, - { - "plugin": "alerting", - "path": "x-pack/plugins/alerting/server/routes/mute_alert.test.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts" @@ -7593,6 +7585,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.test.ts" + }, { "plugin": "home", "path": "src/plugins/home/server/plugin.test.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 2ba536265757dd..e0eaf478c499a0 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-27 +date: 2023-09-28 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 b8232593e40c2a..d9f7d3ef1fae1c 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-27 +date: 2023-09-28 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 5f6150e7fb007d..d925d4100f0693 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-27 +date: 2023-09-28 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 954266d219cd3a..b5a81b286b2b6b 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-27 +date: 2023-09-28 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 7564b892fdec15..53f70c4a7067b9 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-27 +date: 2023-09-28 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 04bd666a92b4b2..2e1acd5b5c686d 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-27 +date: 2023-09-28 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 98706c3e780d8f..d4ef78d2e4bb23 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-27 +date: 2023-09-28 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 efce31e852a4a5..d5bc893b541efc 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-27 +date: 2023-09-28 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 65954d6124e410..7e8c40e7227b66 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-27 +date: 2023-09-28 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 323aef102549ec..b4981db68a8433 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-27 +date: 2023-09-28 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 b837a3b92545f9..8085232ced3d1c 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-27 +date: 2023-09-28 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 a741c13fa5aceb..51e705652da351 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-27 +date: 2023-09-28 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 daed976b33d3b8..fade0b9f8fb83c 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-27 +date: 2023-09-28 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 e3670b884edb93..75da07f2d130fa 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-27 +date: 2023-09-28 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 8ae0c649273fd3..4145c5fa61f34f 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-27 +date: 2023-09-28 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 a7fcc770e5d58f..4a5ec19f755ed1 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-27 +date: 2023-09-28 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 44f8b0f80bd5df..37676b8b0969bf 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-27 +date: 2023-09-28 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 719ca58cbb71ee..70460cdc478df2 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-27 +date: 2023-09-28 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 b27036817417d6..69c8469cd0eea5 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-27 +date: 2023-09-28 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 85080709f83031..69c71f01856562 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-27 +date: 2023-09-28 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 5a4c1a95a06c78..554df492d406c2 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-27 +date: 2023-09-28 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 0a5a0899a03a36..6bff36848c7212 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-27 +date: 2023-09-28 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 dcaebf6fe8729d..5cc136ae0749eb 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-27 +date: 2023-09-28 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 c63d7b7d37470f..e13dcfdb9f38ed 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-27 +date: 2023-09-28 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 82b1c21928b74e..683c297324edb6 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-27 +date: 2023-09-28 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 c09a8f3a694a4e..aa8f917ab4d34d 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-27 +date: 2023-09-28 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 44c0112beb0ac4..2c8699f1e02dd6 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-27 +date: 2023-09-28 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 5af06648592207..8fdb9d50e0ba9c 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-27 +date: 2023-09-28 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 d015938118703d..fb873a0f272db0 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-27 +date: 2023-09-28 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 87514d840bd902..a1fcea7abe8ea3 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-27 +date: 2023-09-28 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 9b08ad8a037d39..cc6a60953615c7 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-27 +date: 2023-09-28 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 a6c1accb9d2a36..0438a2af691aa9 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-27 +date: 2023-09-28 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 5d6c2bcf06b08a..a26e2e5ffac288 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-27 +date: 2023-09-28 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 8a559023beee93..fa66fe5c3dbc48 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-27 +date: 2023-09-28 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 82572885bc3620..078908ff2deb9d 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-27 +date: 2023-09-28 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 2d64edbcad3af7..4e77f9399ccab7 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-27 +date: 2023-09-28 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 d22d98abcac8f9..c69637f7b4ddf3 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-27 +date: 2023-09-28 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 e1e076e60c4413..2825529c4cf74e 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-27 +date: 2023-09-28 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 7b16754cc7f91f..521bd387a4f57a 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-27 +date: 2023-09-28 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 5a8432763f9ceb..e14718e6bc06ea 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-27 +date: 2023-09-28 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 6d46e36846cf9c..73c970639051d9 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-27 +date: 2023-09-28 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 eb63fe9367a217..70ba2d2f95c167 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-27 +date: 2023-09-28 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 df6d0304e3f1c5..3edb04efa05123 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-27 +date: 2023-09-28 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 6133ed94bf32eb..ba406dbd6c411d 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-27 +date: 2023-09-28 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 fbbf5d902cf477..7000629209ee6c 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-27 +date: 2023-09-28 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 06f37273aa76e8..5ad6a91fe4d293 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_core_saved_objects_api_server.devdocs.json index dbbf19f7fb5e7d..de1ed3a7811b10 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -2318,46 +2318,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 68009380ec9be8..6d59ee4a062045 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-27 +date: 2023-09-28 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 44d858a0ea2cae..76d077788665b8 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-27 +date: 2023-09-28 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 0a958f0a9ed228..3562e84112af1b 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-27 +date: 2023-09-28 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 d671e5d248009e..c5f3fa6010e071 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-27 +date: 2023-09-28 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 844c5039b54c57..80e5ed5b00cf79 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-27 +date: 2023-09-28 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 338c47d45fb100..6e075576888211 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-27 +date: 2023-09-28 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 48323a986ec9a6..4e67b70507a85e 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.devdocs.json b/api_docs/kbn_core_saved_objects_common.devdocs.json index 34f58a56a00b1b..00d5b87de088bd 100644 --- a/api_docs/kbn_core_saved_objects_common.devdocs.json +++ b/api_docs/kbn_core_saved_objects_common.devdocs.json @@ -2506,6 +2506,14 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx" @@ -2554,6 +2562,10 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/types.ts" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/types.ts" + }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts" diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index fa9373d45ea171..c5f492f5106dc3 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-27 +date: 2023-09-28 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 571e864de7d122..59b3f1336b5b00 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-27 +date: 2023-09-28 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 9d525035b72e68..a717ce03a9ddf7 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-27 +date: 2023-09-28 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 d0ab744e471e5a..8e7fd5914071c6 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-27 +date: 2023-09-28 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 9b870df3d006d8..cf77d204097053 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index f35b9a7a8e32bb..5f59c9dd45cd77 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -5783,46 +5783,6 @@ "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/simple_saved_object.ts" }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, - { - "plugin": "home", - "path": "src/plugins/home/server/services/sample_data/data_sets/logs_tsdb/saved_objects.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 092e2372e11ddd..121f306390d37e 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-27 +date: 2023-09-28 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 536df1203a13bd..d54314765ee075 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-27 +date: 2023-09-28 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 d8b957e20efcb5..e674795bb7d7a4 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-27 +date: 2023-09-28 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 4114737bc417ae..2e66dac37ee41b 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-27 +date: 2023-09-28 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 9745ed2c76005c..bdbfa32906cba9 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-27 +date: 2023-09-28 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 a4378e09393070..d4e797164e7214 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-27 +date: 2023-09-28 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 d8ee2308081cf1..49c68f88fe8251 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-27 +date: 2023-09-28 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 6638fb740dea71..1403d0bbce1100 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-27 +date: 2023-09-28 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 edb94631e1768b..624d513b8121bd 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-27 +date: 2023-09-28 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 c6ce0c4fd2c6ad..a6a09ae1ca8170 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-27 +date: 2023-09-28 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 c1ad9beeeccb8b..7f83d01655e644 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-27 +date: 2023-09-28 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 095a6edb5f0b79..2b331379945b23 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-27 +date: 2023-09-28 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 49bc099779a62f..46d2ba4365b338 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-27 +date: 2023-09-28 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 ad1e5d907f693d..9858dae8af6998 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-27 +date: 2023-09-28 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 e33c1dd2211188..e90a3fe9e3be71 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-27 +date: 2023-09-28 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 7b0ffda6e36332..e66d8531ab745d 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-27 +date: 2023-09-28 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 2bbb1fbc8a5170..ce753601db8cda 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-27 +date: 2023-09-28 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 9c2c62dd800346..4f2e72185c5f25 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-27 +date: 2023-09-28 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 962b4001f57d09..ed51b6f61c1851 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-27 +date: 2023-09-28 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 3b33e0af61ad8a..aa314d6075295a 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-27 +date: 2023-09-28 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 9b4af9a0986e33..188f58f540939a 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-27 +date: 2023-09-28 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 b09a457320651f..8b5bdae1113e7d 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-27 +date: 2023-09-28 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 c2e28091ddb861..47eedb089d877c 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-27 +date: 2023-09-28 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 1c5dbe324c8f55..208a9a0feb9d74 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-27 +date: 2023-09-28 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 b4ffb257425cb3..88af0ad6e55976 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-27 +date: 2023-09-28 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 94e13c484e0002..e29baf4b5494d3 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-27 +date: 2023-09-28 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 60b85eceb6b413..0a443c67564389 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-27 +date: 2023-09-28 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 ff1f1c51883037..f634383349b8f2 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-27 +date: 2023-09-28 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 5757ab3fcd7f3e..f72ac8aa54458c 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-27 +date: 2023-09-28 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 7fbc1a1c6bfbcd..18ebf327740a80 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-27 +date: 2023-09-28 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 cdc77fe7c1f775..4fe2c6c812b6f4 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-27 +date: 2023-09-28 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 426f9a238f8af4..34164c39ab4442 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-27 +date: 2023-09-28 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 7372b306e47bb2..3c21c81eaf4da7 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-27 +date: 2023-09-28 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 2a5c4641ddf03b..d692dd9599aa24 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-27 +date: 2023-09-28 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 7082fdc9b08622..55ca0a7bf80c21 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-27 +date: 2023-09-28 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 fc85743970e1c7..3d2af8fc0751a4 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-27 +date: 2023-09-28 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 7301f58ed382c9..6c08dce9ef5986 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-27 +date: 2023-09-28 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 5774c855128a32..41d649fd4c0628 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-27 +date: 2023-09-28 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 799b85e2738419..292b91c3856ffe 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-27 +date: 2023-09-28 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 5e0185faae6c8e..5aba148d03168b 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-27 +date: 2023-09-28 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 cf5eec20cc9d0c..29b10d15a50876 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_default_nav_analytics.devdocs.json index 17b5e0d62238c6..0a3d565d12d10e 100644 --- a/api_docs/kbn_default_nav_analytics.devdocs.json +++ b/api_docs/kbn_default_nav_analytics.devdocs.json @@ -172,7 +172,7 @@ "label": "children", "description": [], "signature": [ - "[{ id: \"root\"; children: [{ link: \"discover\"; }, { link: \"dashboards\"; }, { link: \"visualize\"; }]; }]" + "[{ link: \"discover\"; }, { link: \"dashboards\"; }, { link: \"visualize\"; }]" ], "path": "packages/default-nav/analytics/default_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index f07d943d411901..2c47c2d9166879 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_default_nav_devtools.devdocs.json index dbdf1885d31398..c9155ee9f1a892 100644 --- a/api_docs/kbn_default_nav_devtools.devdocs.json +++ b/api_docs/kbn_default_nav_devtools.devdocs.json @@ -172,7 +172,7 @@ "label": "children", "description": [], "signature": [ - "[{ id: \"root\"; children: [{ link: \"dev_tools:console\"; }, { link: \"dev_tools:searchprofiler\"; }, { link: \"dev_tools:grokdebugger\"; }, { link: \"dev_tools:painless_lab\"; }]; }]" + "[{ link: \"dev_tools:console\"; }, { link: \"dev_tools:searchprofiler\"; }, { link: \"dev_tools:grokdebugger\"; }, { link: \"dev_tools:painless_lab\"; }]" ], "path": "packages/default-nav/devtools/default_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index c67e9ca453b3ea..d1a02ac85a8180 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_default_nav_management.devdocs.json index 17e0d18c97a957..8a4ab5949e6f5a 100644 --- a/api_docs/kbn_default_nav_management.devdocs.json +++ b/api_docs/kbn_default_nav_management.devdocs.json @@ -172,7 +172,7 @@ "label": "children", "description": [], "signature": [ - "[{ id: \"root\"; title: string; children: [{ link: \"monitoring\"; }]; }, { id: \"integration_management\"; title: string; children: [{ link: \"integrations\"; }, { link: \"fleet\"; }, { link: \"osquery\"; }]; }, { id: \"stack_management\"; title: string; children: [{ id: \"ingest\"; title: string; children: [{ link: \"management:ingest_pipelines\"; }, { link: \"management:pipelines\"; }]; }, { id: \"data\"; title: string; children: [{ link: \"management:index_management\"; }, { link: \"management:transform\"; }]; }, { id: \"alerts_and_insights\"; title: string; children: [{ link: \"management:triggersActions\"; }, { link: \"management:cases\"; }, { link: \"management:triggersActionsConnectors\"; }, { link: \"management:jobsListLink\"; }]; }, { id: \"kibana\"; title: string; children: [{ link: \"management:dataViews\"; }, { link: \"management:objects\"; }, { link: \"management:tags\"; }, { link: \"management:spaces\"; }, { link: \"management:settings\"; }]; }]; }]" + "[{ link: \"monitoring\"; }, { id: \"integration_management\"; title: string; children: [{ link: \"integrations\"; }, { link: \"fleet\"; }, { link: \"osquery\"; }]; }, { id: \"stack_management\"; title: string; children: [{ id: \"ingest\"; title: string; children: [{ link: \"management:ingest_pipelines\"; }, { link: \"management:pipelines\"; }]; }, { id: \"data\"; title: string; children: [{ link: \"management:index_management\"; }, { link: \"management:transform\"; }]; }, { id: \"alerts_and_insights\"; title: string; children: [{ link: \"management:triggersActions\"; }, { link: \"management:cases\"; }, { link: \"management:triggersActionsConnectors\"; }, { link: \"management:jobsListLink\"; }]; }, { id: \"kibana\"; title: string; children: [{ link: \"management:dataViews\"; }, { link: \"management:objects\"; }, { link: \"management:tags\"; }, { link: \"management:spaces\"; }, { link: \"management:settings\"; }]; }]; }]" ], "path": "packages/default-nav/management/default_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index a91426fa703701..56a49ae0cc9a2a 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_default_nav_ml.devdocs.json index 8124cde80d96fa..789fee35acf132 100644 --- a/api_docs/kbn_default_nav_ml.devdocs.json +++ b/api_docs/kbn_default_nav_ml.devdocs.json @@ -172,7 +172,7 @@ "label": "children", "description": [], "signature": [ - "[{ title: string; id: \"root\"; children: [{ link: \"ml:overview\"; }, { link: \"ml:notifications\"; }]; }, { title: string; id: \"anomaly_detection\"; children: [{ title: string; link: \"ml:anomalyDetection\"; }, { link: \"ml:anomalyExplorer\"; }, { link: \"ml:singleMetricViewer\"; }, { link: \"ml:settings\"; }]; }, { id: \"data_frame_analytics\"; title: string; children: [{ title: string; link: \"ml:dataFrameAnalytics\"; }, { link: \"ml:resultExplorer\"; }, { link: \"ml:analyticsMap\"; }]; }, { id: \"model_management\"; title: string; children: [{ link: \"ml:nodesOverview\"; }, { link: \"ml:nodes\"; }]; }, { id: \"data_visualizer\"; title: string; children: [{ title: string; link: \"ml:fileUpload\"; }, { title: string; link: \"ml:indexDataVisualizer\"; }, { title: string; link: \"ml:dataDrift\"; }]; }, { id: \"aiops_labs\"; title: string; children: [{ link: \"ml:logRateAnalysis\"; }, { link: \"ml:logPatternAnalysis\"; }, { link: \"ml:changePointDetections\"; }]; }]" + "[{ link: \"ml:overview\"; }, { link: \"ml:notifications\"; }, { title: string; id: \"anomaly_detection\"; children: [{ title: string; link: \"ml:anomalyDetection\"; }, { link: \"ml:anomalyExplorer\"; }, { link: \"ml:singleMetricViewer\"; }, { link: \"ml:settings\"; }]; }, { id: \"data_frame_analytics\"; title: string; children: [{ title: string; link: \"ml:dataFrameAnalytics\"; }, { link: \"ml:resultExplorer\"; }, { link: \"ml:analyticsMap\"; }]; }, { id: \"model_management\"; title: string; children: [{ link: \"ml:nodesOverview\"; }, { link: \"ml:nodes\"; }]; }, { id: \"data_visualizer\"; title: string; children: [{ title: string; link: \"ml:fileUpload\"; }, { title: string; link: \"ml:indexDataVisualizer\"; }, { title: string; link: \"ml:dataDrift\"; }]; }, { id: \"aiops_labs\"; title: string; children: [{ link: \"ml:logRateAnalysis\"; }, { link: \"ml:logPatternAnalysis\"; }, { link: \"ml:changePointDetections\"; }]; }]" ], "path": "packages/default-nav/ml/default_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 6fa579a7689100..46926535b1dc2c 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-27 +date: 2023-09-28 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 26e6a05b71bc3f..1e62370f1b7e97 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 4563b143cc9842..b744a4276ad00f 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index f5572fe15612d5..9cecd22fdc35f0 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-27 +date: 2023-09-28 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 5641d1562c1569..116e08ece3b4f1 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-27 +date: 2023-09-28 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 824c794f8aa70e..8e23446898bb5f 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-27 +date: 2023-09-28 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 384d01d5cbef80..22f5ecedc367f9 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-27 +date: 2023-09-28 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 e17aa330e079e4..bc589ba587925f 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-27 +date: 2023-09-28 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 53a36a4b41977d..bd8452f3a6102c 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-27 +date: 2023-09-28 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 f7373e425b5627..f886d9e1f72fe9 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-27 +date: 2023-09-28 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 315bcc59598259..531b4047d81023 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-27 +date: 2023-09-28 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 62309375a0b44a..da4278b0f24e03 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_elastic_assistant.devdocs.json index 06e02662f3e6a1..ede8cebe2845c5 100644 --- a/api_docs/kbn_elastic_assistant.devdocs.json +++ b/api_docs/kbn_elastic_assistant.devdocs.json @@ -745,7 +745,7 @@ "label": "apiConfig", "description": [], "signature": [ - "{ connectorId?: string | undefined; defaultSystemPromptId?: string | undefined; provider?: ", + "{ connectorId?: string | undefined; connectorTypeTitle?: string | undefined; defaultSystemPromptId?: string | undefined; provider?: ", "OpenAiProviderType", " | undefined; model?: string | undefined; }" ], diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 35ef19e267a855..66e87a962a9399 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-27 +date: 2023-09-28 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 859a91626e7676..a21f177dd1087a 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-27 +date: 2023-09-28 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 0dcf8b73ff21df..dfee656986ba32 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-27 +date: 2023-09-28 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 33f053b421a648..472297928e76ca 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.devdocs.json b/api_docs/kbn_es_query.devdocs.json index b43651416b775c..bcee687e1a90b5 100644 --- a/api_docs/kbn_es_query.devdocs.json +++ b/api_docs/kbn_es_query.devdocs.json @@ -3216,7 +3216,7 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | { [key: string]: any; }) => boolean" + " | { [key: string]: any; } | undefined) => boolean" ], "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, @@ -3245,12 +3245,12 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | { [key: string]: any; }" + " | { [key: string]: any; } | undefined" ], "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "isRequired": false } ], "returnComment": [], diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 8d11b2cb7c7fa8..a4dd3216a0b018 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-27 +date: 2023-09-28 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 6a83b5a69bf676..90a8ed9e98666d 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-27 +date: 2023-09-28 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 d929ffa5ce38cd..7e3a61cda69526 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-27 +date: 2023-09-28 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 48d3a939dc3097..6a2505c663d65d 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-27 +date: 2023-09-28 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 a73e13aac9e7c2..4ff534569925c2 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-27 +date: 2023-09-28 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 05dbf3774eba9c..9f07c4635c4a71 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-27 +date: 2023-09-28 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 3f373d1ccbd6d1..69ab90341b498b 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-27 +date: 2023-09-28 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 3a3aa627686dd5..f17ad7ae6202e4 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-27 +date: 2023-09-28 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 e6b99ec4178cec..40777ac9193b4b 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-27 +date: 2023-09-28 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 d43128fc05055d..e343b48f3a7fcc 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-27 +date: 2023-09-28 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 82994f46fd7ab8..9843c4d219c1e9 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-27 +date: 2023-09-28 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 252fa6a0d2557b..79e1f9c19fb71d 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-27 +date: 2023-09-28 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 243dcdff9977d7..b9702b01d7c451 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-27 +date: 2023-09-28 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 d91455f06bc14b..071db8d4ad27d4 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-27 +date: 2023-09-28 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 a8ba0be4125d71..ac79c85fa8ec68 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-27 +date: 2023-09-28 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 7b20e948dcc046..dcc6fb20b9bcbd 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-27 +date: 2023-09-28 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 14db74c00e93eb..c8634f2261ce57 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-27 +date: 2023-09-28 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 49e84102eea632..d31168b65d591c 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-27 +date: 2023-09-28 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 8957d6d55e1931..d0fe5ae21bbd34 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-27 +date: 2023-09-28 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 f2f3e0d2c5e84f..6365ba964cd7fd 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-27 +date: 2023-09-28 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 125217e69bcc16..83826ec32c0754 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-27 +date: 2023-09-28 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 23f1b09b8adc69..4defa432ad86ed 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-27 +date: 2023-09-28 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 2a1fed54f342c5..e02b981ea3546b 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-27 +date: 2023-09-28 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 16f67a571b4751..4abcf85aaf8701 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-27 +date: 2023-09-28 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 b3609a476b3aa6..f0e6c22e997174 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-27 +date: 2023-09-28 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 86de7b3ef0fad2..c25eb7c8bf940d 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-27 +date: 2023-09-28 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 e11e02d06c7f3d..e94e0c092caae0 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-27 +date: 2023-09-28 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 32b836d76b668b..2e7231863ff76b 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-27 +date: 2023-09-28 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 7c4909f3683ff8..8fd5a7ef11ae49 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-27 +date: 2023-09-28 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 3f1803d50dcd6d..bdcf9b2f524155 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-27 +date: 2023-09-28 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 da2f861a57d272..9489ac900110de 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-27 +date: 2023-09-28 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 5601414cdbf3d1..a0146c79602425 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-27 +date: 2023-09-28 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 59c4b7b589d042..b96907067c4dbd 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-27 +date: 2023-09-28 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 fe6f47de8bc014..e9feca276bc8e4 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-27 +date: 2023-09-28 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 e9adeb65ea66f7..ec1bcf3885a367 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-27 +date: 2023-09-28 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 36d7fa77ab318b..148678fdfa01f1 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-27 +date: 2023-09-28 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 52efaac0bdf96f..6fe1b473d3b0cf 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index e6162d473c8dfc..91c5441bebc84e 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2023-09-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 51a1a7e25788ad..23a1088ee7ef3d 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-27 +date: 2023-09-28 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 e9bbfbb080329a..30bd79f1b35ae9 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-27 +date: 2023-09-28 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 80da205287a5b1..dd8052acb1b980 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-27 +date: 2023-09-28 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 bd8d4a29c4df36..4cdcb7214472aa 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-27 +date: 2023-09-28 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 74a24e7dad5c92..9b7e11335d67a7 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-27 +date: 2023-09-28 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 61410de80c13e7..4ad452c18fe8d3 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-27 +date: 2023-09-28 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 3007888a03abbb..be8f0fec4c0a47 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-27 +date: 2023-09-28 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 2e0889fc10fe64..171172230f811b 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-27 +date: 2023-09-28 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 e8b7ff4e2b1a84..54c67af908275f 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-27 +date: 2023-09-28 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 3287e6a0e3dafb..0c892a58f18189 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-27 +date: 2023-09-28 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 6500398277e666..bb895312ff9583 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.devdocs.json b/api_docs/kbn_ml_chi2test.devdocs.json new file mode 100644 index 00000000000000..d5adcc897813fb --- /dev/null +++ b/api_docs/kbn_ml_chi2test.devdocs.json @@ -0,0 +1,269 @@ +{ + "id": "@kbn/ml-chi2test", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.computeChi2PValue", + "type": "Function", + "tags": [], + "label": "computeChi2PValue", + "description": [ + "\nCompute the p-value for how similar the datasets are.\nReturned value ranges from 0 to 1, with 1 meaning the datasets are identical.\n" + ], + "signature": [ + "(normalizedBaselineTerms: ", + { + "pluginId": "@kbn/ml-chi2test", + "scope": "common", + "docId": "kibKbnMlChi2testPluginApi", + "section": "def-common.Histogram", + "text": "Histogram" + }, + "[], normalizedDriftedTerms: ", + { + "pluginId": "@kbn/ml-chi2test", + "scope": "common", + "docId": "kibKbnMlChi2testPluginApi", + "section": "def-common.Histogram", + "text": "Histogram" + }, + "[]) => number" + ], + "path": "x-pack/packages/ml/chi2test/compute_chi_2_pvalue.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.computeChi2PValue.$1", + "type": "Array", + "tags": [], + "label": "normalizedBaselineTerms", + "description": [ + "- An array of normalized baseline terms (Histogram objects)." + ], + "signature": [ + { + "pluginId": "@kbn/ml-chi2test", + "scope": "common", + "docId": "kibKbnMlChi2testPluginApi", + "section": "def-common.Histogram", + "text": "Histogram" + }, + "[]" + ], + "path": "x-pack/packages/ml/chi2test/compute_chi_2_pvalue.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.computeChi2PValue.$2", + "type": "Array", + "tags": [], + "label": "normalizedDriftedTerms", + "description": [ + "- An array of normalized drifted terms (Histogram objects)." + ], + "signature": [ + { + "pluginId": "@kbn/ml-chi2test", + "scope": "common", + "docId": "kibKbnMlChi2testPluginApi", + "section": "def-common.Histogram", + "text": "Histogram" + }, + "[]" + ], + "path": "x-pack/packages/ml/chi2test/compute_chi_2_pvalue.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "The p-value indicating the similarity of the datasets." + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.criticalTableLookup", + "type": "Function", + "tags": [ + "throws" + ], + "label": "criticalTableLookup", + "description": [ + "\nPerforms a lookup in a critical values table to determine the significance level\nassociated with a given chi-squared statistic and degrees of freedom.\n" + ], + "signature": [ + "(chi2Statistic: number, df: number) => number" + ], + "path": "x-pack/packages/ml/chi2test/critical_table_lookup.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.criticalTableLookup.$1", + "type": "number", + "tags": [], + "label": "chi2Statistic", + "description": [ + "- The chi-squared statistic for which the significance level is to be determined." + ], + "signature": [ + "number" + ], + "path": "x-pack/packages/ml/chi2test/critical_table_lookup.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.criticalTableLookup.$2", + "type": "number", + "tags": [], + "label": "df", + "description": [ + "- The degrees of freedom (an integer) for the chi-squared test." + ], + "signature": [ + "number" + ], + "path": "x-pack/packages/ml/chi2test/critical_table_lookup.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "The significance level corresponding to the chi-squared statistic and degrees of freedom." + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.Histogram", + "type": "Interface", + "tags": [], + "label": "Histogram", + "description": [ + "\nInterface for the Histogram type used by computeChi2PValue." + ], + "path": "x-pack/packages/ml/chi2test/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.Histogram.doc_count", + "type": "number", + "tags": [], + "label": "doc_count", + "description": [ + "\nThe doc count." + ], + "path": "x-pack/packages/ml/chi2test/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.Histogram.key", + "type": "CompoundType", + "tags": [], + "label": "key", + "description": [ + "\nThe key." + ], + "signature": [ + "string | number" + ], + "path": "x-pack/packages/ml/chi2test/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.Histogram.percentage", + "type": "number", + "tags": [], + "label": "percentage", + "description": [ + "\nOptional percentage." + ], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/ml/chi2test/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.CRITICAL_VALUES_TABLE", + "type": "Array", + "tags": [], + "label": "CRITICAL_VALUES_TABLE", + "description": [ + "\nTable generated from following python code\n\nimport scipy.stats as stats\nimport numpy as np\n\n# generate a chi-squared critical value table\n\n# degrees of freedom\ndf = range(1,100)\n\n# levels of significance\nsignificance_levels = np.concatenate((np.logspace(-6, -3, 3), np.linspace(0.01, 0.99, 99)))\n\n# create the table\ntable = []\nfor d in df:\n row = []\n for l in significance_levels:\n row.append(round(stats.chi2.ppf(1 - l, d), 2))\n table.append(row)\n\ncritical_value_table = np.array(table)\n\n# print the critical value table as a TypeScipt array\nprint(\"export const CRITICAL_VALUES_TABLE = [\")\nfor row in critical_value_table:\n print(f\" [{', '.join([str(x) for x in row])}],\")\nprint(\"];\")\n\n# print the significance levels as a TypeScript array\nprint(\"export const SIGNIFICANCE_LEVELS = [\")\nprint(f\" {', '.join([f'{x:.6f}' for x in significance_levels])}\")\nprint(\"];\")\n\nuntil we find a low size replacement for doing chi2test in js" + ], + "signature": [ + "number[][]" + ], + "path": "x-pack/packages/ml/chi2test/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ml-chi2test", + "id": "def-common.SIGNIFICANCE_LEVELS", + "type": "Array", + "tags": [], + "label": "SIGNIFICANCE_LEVELS", + "description": [ + "\nSignifance levels used by `computeChi2PValue`." + ], + "signature": [ + "number[]" + ], + "path": "x-pack/packages/ml/chi2test/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx new file mode 100644 index 00000000000000..e6db0c8150575b --- /dev/null +++ b/api_docs/kbn_ml_chi2test.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnMlChi2testPluginApi +slug: /kibana-dev-docs/api/kbn-ml-chi2test +title: "@kbn/ml-chi2test" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/ml-chi2test plugin +date: 2023-09-28 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] +--- +import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; + + + +Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 12 | 0 | 0 | 0 | + +## Common + +### Functions + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index e529c52caf1a98..08aff6980d2487 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-27 +date: 2023-09-28 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 afbafb7b587ad4..4133de8b78c3ca 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_ml_date_picker.devdocs.json index 77ed2b13c1320e..333b007030ad41 100644 --- a/api_docs/kbn_ml_date_picker.devdocs.json +++ b/api_docs/kbn_ml_date_picker.devdocs.json @@ -546,12 +546,12 @@ }, { "parentPluginId": "@kbn/ml-date-picker", - "id": "def-common.DatePickerDependencies.isServerless", + "id": "def-common.DatePickerDependencies.showFrozenDataTierChoice", "type": "CompoundType", "tags": [], - "label": "isServerless", + "label": "showFrozenDataTierChoice", "description": [ - "\nOptional flag to indicate whether kibana is running in serverless" + "\nOptional flag to disable the frozen data tier choice." ], "signature": [ "boolean | undefined" @@ -951,22 +951,6 @@ "path": "x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "@kbn/ml-date-picker", - "id": "def-common.FullTimeRangeSelectorProps.hideFrozenDataTierChoice", - "type": "CompoundType", - "tags": [], - "label": "hideFrozenDataTierChoice", - "description": [ - "\nOptional flag to disable the frozen data tier choice." - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index a67fa215506be9..65355d8ab5c046 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 49 | 0 | 0 | 0 | +| 48 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 15b3d91b13d518..9b406da6dcad91 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-27 +date: 2023-09-28 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 90bbb7a1d27e3e..22ad62d73b583b 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-27 +date: 2023-09-28 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 1891292f4ed1e9..77bf076f4abfdc 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-27 +date: 2023-09-28 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 89ce3a96a258b5..07d9aedac55265 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-27 +date: 2023-09-28 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 a8eb4837cf39ab..b24f60582ea295 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-27 +date: 2023-09-28 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 74e783b9794113..445daff4e58f66 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-27 +date: 2023-09-28 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 0d5bc3917d2528..1e8eef4aafa4a5 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-27 +date: 2023-09-28 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 d7679099893e1a..5c55088883f20e 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-27 +date: 2023-09-28 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 f372e630c4e5ea..7b21c59ef5a46a 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-27 +date: 2023-09-28 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 efb092b933acbe..57446eff69ef42 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-27 +date: 2023-09-28 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 c9924cbc05cdf3..bcae0b67f88b0b 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-27 +date: 2023-09-28 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 e417dddd1500e7..3eefcc9e9ca40a 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-27 +date: 2023-09-28 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 20bff84eeddea5..e4f86dcbb89a8b 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-27 +date: 2023-09-28 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 ad6a5e21e80dc4..af3dab5b7ccd83 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 25cafd41b82b01..27108572f4e4b6 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 053d481c11e535..d9f4892631de7a 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-27 +date: 2023-09-28 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 2005f4fc00f433..699938fc3fbe35 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-27 +date: 2023-09-28 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 c7714e82de8273..61e53db7164cae 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-27 +date: 2023-09-28 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 5881d6c4fb628b..db29880d10a290 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-27 +date: 2023-09-28 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.mdx b/api_docs/kbn_openapi_generator.mdx index 219dcf71679ed7..e34b9e16604cb5 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2023-09-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 547c155ee1cef1..a70d81ee2c9792 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-27 +date: 2023-09-28 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 9ff131a7535bda..5bb7a5a3a3c9ff 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-27 +date: 2023-09-28 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 6f378f89bd741f..1d4e68e64d45c4 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-27 +date: 2023-09-28 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 f36ba0465f8f5f..878129557b2d46 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-27 +date: 2023-09-28 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 285b1089dbacde..082f1de03f775c 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-27 +date: 2023-09-28 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 04191a7624fc03..56b6a83cce3a3e 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-27 +date: 2023-09-28 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 417b481388307b..3ad2e3cf411082 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-27 +date: 2023-09-28 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 b27456b36309e2..3179689b14c3f6 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-27 +date: 2023-09-28 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 16acacdcea4889..8a2d417fae7f33 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-27 +date: 2023-09-28 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 e26c8e12273f0f..1876ea26da9e72 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-27 +date: 2023-09-28 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 75ffb92c6eca5f..cc294d648fc00c 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-27 +date: 2023-09-28 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 f64b81f56443fd..7aa5a465ee3d6e 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-27 +date: 2023-09-28 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 3fd5e175a3a2bb..f0b1e851011318 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-27 +date: 2023-09-28 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 a87c6120b8b6e9..dd39572ba4528e 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-27 +date: 2023-09-28 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 296dca6f004526..973cc4c906c300 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-27 +date: 2023-09-28 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 afc47b50c05249..94853405f382e3 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-27 +date: 2023-09-28 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 6cf2ecf79c791d..fcae8cf4105062 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-27 +date: 2023-09-28 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 39a66eeadb8253..da97d5b1153012 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-27 +date: 2023-09-28 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 035be841006a2a..06a952bee9d6ac 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-27 +date: 2023-09-28 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 f16e80a6a006d7..5b4a284402274b 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.devdocs.json b/api_docs/kbn_resizable_layout.devdocs.json new file mode 100644 index 00000000000000..5c109cbf176467 --- /dev/null +++ b/api_docs/kbn_resizable_layout.devdocs.json @@ -0,0 +1,321 @@ +{ + "id": "@kbn/resizable-layout", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayout", + "type": "Function", + "tags": [], + "label": "ResizableLayout", + "description": [], + "signature": [ + "React.ForwardRefExoticComponent<", + { + "pluginId": "@kbn/resizable-layout", + "scope": "common", + "docId": "kibKbnResizableLayoutPluginApi", + "section": "def-common.ResizableLayoutProps", + "text": "ResizableLayoutProps" + }, + " & React.RefAttributes<{}>>" + ], + "path": "packages/kbn-resizable-layout/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayout.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps", + "type": "Interface", + "tags": [], + "label": "ResizableLayoutProps", + "description": [], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.className", + "type": "string", + "tags": [], + "label": "className", + "description": [ + "\nClass name for the layout container" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.mode", + "type": "Enum", + "tags": [], + "label": "mode", + "description": [ + "\nThe current layout mode" + ], + "signature": [ + { + "pluginId": "@kbn/resizable-layout", + "scope": "common", + "docId": "kibKbnResizableLayoutPluginApi", + "section": "def-common.ResizableLayoutMode", + "text": "ResizableLayoutMode" + } + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.direction", + "type": "Enum", + "tags": [], + "label": "direction", + "description": [ + "\nThe current layout direction" + ], + "signature": [ + { + "pluginId": "@kbn/resizable-layout", + "scope": "common", + "docId": "kibKbnResizableLayoutPluginApi", + "section": "def-common.ResizableLayoutDirection", + "text": "ResizableLayoutDirection" + } + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.container", + "type": "CompoundType", + "tags": [], + "label": "container", + "description": [ + "\nThe parent container element, used to calculate the layout size" + ], + "signature": [ + "HTMLElement | null" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.fixedPanelSize", + "type": "number", + "tags": [], + "label": "fixedPanelSize", + "description": [ + "\nCurrent size of the fixed panel in pixels" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.minFixedPanelSize", + "type": "number", + "tags": [], + "label": "minFixedPanelSize", + "description": [ + "\nMinimum size of the fixed panel in pixels" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.minFlexPanelSize", + "type": "number", + "tags": [], + "label": "minFlexPanelSize", + "description": [ + "\nMinimum size of the flex panel in pixels" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.fixedPanel", + "type": "Object", + "tags": [], + "label": "fixedPanel", + "description": [ + "\nThe fixed panel" + ], + "signature": [ + "React.ReactElement>" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.flexPanel", + "type": "Object", + "tags": [], + "label": "flexPanel", + "description": [ + "\nThe flex panel" + ], + "signature": [ + "React.ReactElement>" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.resizeButtonClassName", + "type": "string", + "tags": [], + "label": "resizeButtonClassName", + "description": [ + "\nClass name for the resize button" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.datatestsubj", + "type": "string", + "tags": [], + "label": "['data-test-subj']", + "description": [ + "\nTest subject for the layout container" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.onFixedPanelSizeChange", + "type": "Function", + "tags": [], + "label": "onFixedPanelSizeChange", + "description": [ + "\nCallback when the fixed panel size changes, receives the new size in pixels" + ], + "signature": [ + "((fixedPanelSize: number) => void) | undefined" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutProps.onFixedPanelSizeChange.$1", + "type": "number", + "tags": [], + "label": "fixedPanelSize", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-resizable-layout/src/resizable_layout.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [ + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutDirection", + "type": "Enum", + "tags": [], + "label": "ResizableLayoutDirection", + "description": [], + "path": "packages/kbn-resizable-layout/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/resizable-layout", + "id": "def-common.ResizableLayoutMode", + "type": "Enum", + "tags": [], + "label": "ResizableLayoutMode", + "description": [], + "path": "packages/kbn-resizable-layout/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx new file mode 100644 index 00000000000000..0da03531014def --- /dev/null +++ b/api_docs/kbn_resizable_layout.mdx @@ -0,0 +1,36 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnResizableLayoutPluginApi +slug: /kibana-dev-docs/api/kbn-resizable-layout +title: "@kbn/resizable-layout" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/resizable-layout plugin +date: 2023-09-28 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] +--- +import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; + +A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. + +Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 18 | 0 | 5 | 0 | + +## Common + +### Functions + + +### Interfaces + + +### Enums + + diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index b7a71a784b7bdf..31a2117d123f70 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-27 +date: 2023-09-28 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 1d2daea227c932..a3b899296fc13b 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.devdocs.json b/api_docs/kbn_rule_data_utils.devdocs.json index ade3b78ed3eaad..08e83e70c07525 100644 --- a/api_docs/kbn_rule_data_utils.devdocs.json +++ b/api_docs/kbn_rule_data_utils.devdocs.json @@ -988,6 +988,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/rule-data-utils", + "id": "def-common.ALERT_STATUS_UNTRACKED", + "type": "string", + "tags": [], + "label": "ALERT_STATUS_UNTRACKED", + "description": [], + "signature": [ + "\"untracked\"" + ], + "path": "packages/kbn-rule-data-utils/src/alerts_as_data_status.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/rule-data-utils", "id": "def-common.ALERT_SUPPRESSION_DOCS_COUNT", @@ -1386,7 +1401,7 @@ "label": "AlertStatus", "description": [], "signature": [ - "\"recovered\" | \"active\"" + "\"recovered\" | \"active\" | \"untracked\"" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_status.ts", "deprecated": false, diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 9457d7b39e6210..571272bb62c8ce 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detections-response](https://github.com/orgs/elastic/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 110 | 0 | 107 | 0 | +| 111 | 0 | 108 | 0 | ## Common diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index d331b779ebc782..be6f5455c1eb98 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-27 +date: 2023-09-28 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 86f2f7b04a67d0..cd554311196eaf 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-27 +date: 2023-09-28 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 df1c293d4ac719..f9d60b8f9830ee 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-27 +date: 2023-09-28 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 6738831cc0ddd3..3add0cf0ca91a1 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-27 +date: 2023-09-28 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 2be45374fbd1bf..9f0b5946914d2e 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-27 +date: 2023-09-28 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 dec912eed480fb..e71b6e751bcec4 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-27 +date: 2023-09-28 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 e6bae75fac7a2f..46ca52301541c4 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-27 +date: 2023-09-28 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 36161e9ab0224d..acb13a49106ee8 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-27 +date: 2023-09-28 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 37a4b7de0228be..e0742f90564bef 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-27 +date: 2023-09-28 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 b896b9a51f10e2..67ef3bc677b5a1 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-27 +date: 2023-09-28 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 21d23f73aff57c..7ad20ca1350808 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-27 +date: 2023-09-28 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 e7f8138610840e..9c4763df268d37 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-27 +date: 2023-09-28 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 9df0aef9aae3b5..adbb7f980e1d10 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-27 +date: 2023-09-28 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 33f6edde074e53..9546f1027f1fd2 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-27 +date: 2023-09-28 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 465ee9a5a8a251..474ab33badccb2 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-27 +date: 2023-09-28 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 4ec29cc06ee0cf..fb9fa1691cfb85 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-27 +date: 2023-09-28 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 94abe89c8af858..e6f0e5883981b6 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-27 +date: 2023-09-28 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 368e0101c05025..1b3c5205203cd5 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-27 +date: 2023-09-28 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 a530d1f08faf7b..5db08ab670b0f6 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-27 +date: 2023-09-28 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 a09fbb9f9535e4..5f1cbfae2ddcea 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-27 +date: 2023-09-28 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 0b682e3ae24e2f..04c4bac4bc6f01 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-27 +date: 2023-09-28 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 8ee5dd0ba9a7d9..8a9f50538250a6 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-27 +date: 2023-09-28 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 b2dcabe57b8b06..80ce37577fd674 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-27 +date: 2023-09-28 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 17225817fd2c3e..03851b463ee33e 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-27 +date: 2023-09-28 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 aedf825af213c5..79452d333e00fd 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-27 +date: 2023-09-28 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 67266fccb4a0e4..1c49012c189ae2 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-27 +date: 2023-09-28 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 756df4ed8a01ff..b044d07b2b74e2 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-27 +date: 2023-09-28 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 587b6e86533449..6fc1397f9e250a 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-27 +date: 2023-09-28 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 1d04f6475bec55..e72917480c3d11 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-27 +date: 2023-09-28 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 0679a0d7ef9562..0ab2efeebeb3b3 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-27 +date: 2023-09-28 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 d4b6052be73f9c..cb1d60f3c5472d 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-27 +date: 2023-09-28 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 eeeb24440cddc0..5f925879b8bc1b 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-27 +date: 2023-09-28 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 74cd48bb9f1c85..0895892d63e298 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-27 +date: 2023-09-28 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 59e8cdba5c0fb8..9ac7afdbc7c12e 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-27 +date: 2023-09-28 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 e0c8eec4af2c83..552a5a364b893c 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-27 +date: 2023-09-28 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 99320011304da2..ce7f3112ea9d84 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-27 +date: 2023-09-28 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 12c4d3068feec0..82a2143f27a8c6 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-27 +date: 2023-09-28 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 fbce9b8fae864d..23983a88ea976c 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-27 +date: 2023-09-28 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 016fca3d9b34f3..319220a3e38bf0 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 7f436b3e1b0ce2..2df6d918959e9a 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-27 +date: 2023-09-28 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 b42333e9a8394d..77506da9858ea4 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-27 +date: 2023-09-28 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 8eb9170b4a1077..6395c0006637db 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json index 56de2f6b449929..dbe91dc51e4469 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json +++ b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json @@ -589,6 +589,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/shared-ux-chrome-navigation", + "id": "def-common.GroupDefinition.accordionProps", + "type": "Object", + "tags": [], + "label": "accordionProps", + "description": [], + "signature": [ + "Partial<", + "EuiAccordionProps", + "> | undefined" + ], + "path": "packages/shared-ux/chrome/navigation/src/ui/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", "id": "def-common.GroupDefinition.preset", diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index ee119af49d9202..e55302bbe8eab0 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.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 | |-------------------|-----------|------------------------|-----------------| -| 46 | 0 | 37 | 4 | +| 47 | 0 | 38 | 4 | ## Common diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 385531c829f1ab..7649034f0d3e87 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-27 +date: 2023-09-28 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 c4fb767bd84b21..c6f19cb0fbf6df 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-27 +date: 2023-09-28 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 06da3942b17721..51a59254e147ce 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-27 +date: 2023-09-28 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 cf233599761f9d..40f59765cbf293 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-27 +date: 2023-09-28 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 9a62b1176d6ae2..29352f31681b78 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-27 +date: 2023-09-28 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 614153b8bbe7ce..d2a767e9edcdaa 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-27 +date: 2023-09-28 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 2c9fad240a92f6..a667bfd932d2c1 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-27 +date: 2023-09-28 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 b6b1ceb6a166ab..c75b5fe1da2f86 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-27 +date: 2023-09-28 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 17e4eb4556b4c7..cc0af31e59b71d 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-27 +date: 2023-09-28 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 2a1292c9b521fb..65a44d4a48c00f 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-27 +date: 2023-09-28 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 485ce8950b3caa..f9f156e6513588 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_shared_ux_markdown_mocks.devdocs.json index ff47a835e883e8..c37175744b0e93 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.devdocs.json +++ b/api_docs/kbn_shared_ux_markdown_mocks.devdocs.json @@ -433,31 +433,8 @@ "label": "getServices", "description": [], "signature": [ - "() => { prefix?: string | undefined; value?: string | undefined; id?: string | undefined; defaultValue?: string | number | readonly string[] | undefined; security?: string | undefined; children?: React.ReactNode; onChange?: ((value: string) => void) | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; className?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; hidden?: boolean | undefined; lang?: string | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; title?: string | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; color?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"search\" | \"none\" | \"text\" | \"url\" | \"email\" | \"tel\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: Booleanish | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"both\" | \"inline\" | undefined; 'aria-busy'?: Booleanish | undefined; 'aria-checked'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"page\" | \"date\" | \"true\" | \"false\" | \"location\" | \"time\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: Booleanish | undefined; 'aria-dropeffect'?: \"execute\" | \"link\" | \"none\" | \"copy\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: Booleanish | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: Booleanish | undefined; 'aria-haspopup'?: boolean | \"true\" | \"false\" | \"grid\" | \"menu\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: Booleanish | undefined; 'aria-invalid'?: boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: Booleanish | undefined; 'aria-multiline'?: Booleanish | undefined; 'aria-multiselectable'?: Booleanish | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"true\" | \"false\" | \"mixed\" | undefined; 'aria-readonly'?: Booleanish | undefined; 'aria-relevant'?: \"text\" | \"all\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: Booleanish | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: Booleanish | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onError?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDown?: React.KeyboardEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; css?: ", - "Interpolation", - "<", - "Theme", - ">; errors?: ", - "EuiMarkdownParseError", - "[] | undefined; height?: number | \"full\" | undefined; readOnly: boolean; maxHeight?: number | undefined; autoExpandPreview?: boolean | undefined; parsingPluginList?: ", - "PluggableList", - "<", - "Settings", - "> | undefined; processingPluginList?: ", - "PluggableList", - "<", - "Settings", - "> | undefined; onParse?: ((error: ", - "EuiMarkdownParseError", - " | null, data: { messages: ", - "VFileMessage", - "[]; ast: ", - "EuiMarkdownAstNode", - "; }) => void) | undefined; initialViewMode?: ", - "MARKDOWN_MODE", - " | undefined; dropHandlers?: ", - "EuiMarkdownDropHandler", - "[] | undefined; markdownContent?: string | undefined; ariaLabelContent?: string | undefined; openLinksInNewTab?: boolean | undefined; }" + "() => ", + "MarkdownProps" ], "path": "packages/shared-ux/markdown/mocks/storybook.ts", "deprecated": false, diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 774bb039c75886..616baf9109a57e 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-27 +date: 2023-09-28 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 9fa3f52b99257e..583fdd1db6d2cc 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-27 +date: 2023-09-28 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 2be08369a35e14..dbce4f323217f3 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-27 +date: 2023-09-28 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 bdb8928d0c5bae..98e62180b45ec4 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-27 +date: 2023-09-28 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 f6f63c303c8219..0adf36511eb075 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-27 +date: 2023-09-28 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 a0eb735153a16d..f5a50185c07380 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-27 +date: 2023-09-28 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 d65f98c2e3e788..028d2eda96e251 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-27 +date: 2023-09-28 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 b558dd4d0dc0a2..4d90a29ad9f5f1 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-27 +date: 2023-09-28 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 32f465acd65785..fe65189ee48d14 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-27 +date: 2023-09-28 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 24f6eaff630a5d..ee0280596d6343 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-27 +date: 2023-09-28 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 0be4859618c224..8ac62210d250ec 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-27 +date: 2023-09-28 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 0bac9cb042e0e3..412a2d5d73aa7c 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 8a653a8cbd33e2..e4ece5d3de0c7a 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-27 +date: 2023-09-28 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 04c8b99f0abad7..966e55209aa84e 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-27 +date: 2023-09-28 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 286d0c6b4b1e0b..ac49b887bb51e6 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-27 +date: 2023-09-28 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 42ea3c53d71f16..27e0fad1c5e26b 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-27 +date: 2023-09-28 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 97ff70d8cdc969..521fcbc5715472 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-27 +date: 2023-09-28 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 e8e2e12ef753e3..d741b88cd5183d 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-27 +date: 2023-09-28 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 1e03c2c77b2d6b..c2bb310e7b829e 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-27 +date: 2023-09-28 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 22b4a0cf54d9d5..8c30da909d2032 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-27 +date: 2023-09-28 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 cfb7e2d5ca1b46..708169be81a995 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-27 +date: 2023-09-28 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 30943d85fac586..9302f6be993c21 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-27 +date: 2023-09-28 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 485368b747e3bc..d7f33b386aac3e 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-27 +date: 2023-09-28 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 84d799396462e2..55b91e59b0a759 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-27 +date: 2023-09-28 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 1e3e5152b75e10..bc5ad8eae4f36b 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-27 +date: 2023-09-28 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 4ff262df0845eb..ab081a92b82fb0 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-27 +date: 2023-09-28 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 c4997d5cdea904..64c7815d0b5978 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index f99a93978c4391..35e27bc8564f20 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 98d00486ae8364..346b18ef1d64ee 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-27 +date: 2023-09-28 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 72d508123f3b37..e10be8a87ee405 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-27 +date: 2023-09-28 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 fa6d8ef8180081..9adda79f97a43b 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-27 +date: 2023-09-28 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 fe3bd910097953..60522e9769d409 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-27 +date: 2023-09-28 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 d4f5fd6be2b84f..b06bc32a5fd00e 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-27 +date: 2023-09-28 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 9477aa1003fe15..e939c892ed6c61 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-27 +date: 2023-09-28 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 fe9f513f152abb..16594f38fdeccf 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-27 +date: 2023-09-28 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 17f7ff4fc1644f..a62c37fd2c0177 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-27 +date: 2023-09-28 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 7688303dd24d2f..8d192906ea3e60 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-27 +date: 2023-09-28 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 964df8b7e4bd11..0a24e5335869b8 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-27 +date: 2023-09-28 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 5d9ea1b472bc40..1068b890ff107a 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-27 +date: 2023-09-28 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.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index d8aeafc25ecbe8..58dc50412912c0 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -5332,6 +5332,21 @@ "deprecated": false, "trackAdoption": false, "children": [ + { + "parentPluginId": "@kbn/unified-field-list", + "id": "def-common.UnifiedFieldListSidebarContainerApi.isSidebarCollapsed$", + "type": "Object", + "tags": [], + "label": "isSidebarCollapsed$", + "description": [], + "signature": [ + "Observable", + "" + ], + "path": "packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/unified-field-list", "id": "def-common.UnifiedFieldListSidebarContainerApi.refetchFieldsExistenceInfo", diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index fe9b7b3dca9d51..6a49b4646622c5 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 303 | 0 | 276 | 9 | +| 304 | 0 | 277 | 9 | ## Common diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 3cdae17bba528e..26e402080d3fcb 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-27 +date: 2023-09-28 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 695f1cd9c419b4..28b2af411cb4f6 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-27 +date: 2023-09-28 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 108a9cea1cf740..16be8cdc9c8e0a 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-27 +date: 2023-09-28 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 101cfc47c066ff..d07714300e6b00 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-27 +date: 2023-09-28 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 d8323dc1f5d55f..33c9bc9df91a59 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-27 +date: 2023-09-28 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 81e02ed89ced1a..8a747ed52c5586 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 005fc460fdc095..e60503ecae3879 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-27 +date: 2023-09-28 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 d2da9c3b44a9c5..c64bf054548aa2 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-27 +date: 2023-09-28 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 32f540c0cf8c73..74c8140a1348d6 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-27 +date: 2023-09-28 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 65680f2090af1b..ec4bd0cba68c06 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index ae753a890a1f4f..80d17157a337c4 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index 6527ea3309bb97..6701b3646dc854 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-27 +date: 2023-09-28 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 b2c25bb409539c..c64e263d410780 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 093458c12f8fa0..c3d51198daa326 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -34,7 +34,13 @@ "text": "LensEmbeddableInput" }, ", ", - "LensEmbeddableOutput", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensEmbeddableOutput", + "text": "LensEmbeddableOutput" + }, ", any> implements ", { "pluginId": "embeddable", @@ -350,7 +356,9 @@ "type": "Function", "tags": [], "label": "updateVisualization", - "description": [], + "description": [ + "\nGets the Lens embeddable's datasource and visualization states\nupdates the embeddable input" + ], "signature": [ "(datasourceState: unknown, visualizationState: unknown) => Promise" ], @@ -391,6 +399,38 @@ ], "returnComment": [] }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.updateByRefInput", + "type": "Function", + "tags": [], + "label": "updateByRefInput", + "description": [], + "signature": [ + "(savedObjectId: string) => void" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.updateByRefInput.$1", + "type": "string", + "tags": [], + "label": "savedObjectId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "lens", "id": "def-public.Embeddable.openConfingPanel", @@ -657,6 +697,22 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "lens", + "id": "def-public.Embeddable.getIsEditable", + "type": "Function", + "tags": [], + "label": "getIsEditable", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "lens", "id": "def-public.Embeddable.inputIsRefType", @@ -3110,6 +3166,58 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "lens", + "id": "def-public.LensEmbeddableOutput", + "type": "Interface", + "tags": [], + "label": "LensEmbeddableOutput", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensEmbeddableOutput", + "text": "LensEmbeddableOutput" + }, + " extends ", + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableOutput", + "text": "EmbeddableOutput" + } + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensEmbeddableOutput.indexPatterns", + "type": "Array", + "tags": [], + "label": "indexPatterns", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "lens", "id": "def-public.LensPublicSetup", diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 3fa0988c2fb337..7cd47709292270 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 617 | 0 | 520 | 61 | +| 622 | 0 | 524 | 60 | ## Client diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 70a18fffb91a30..13ef1ab394700b 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-27 +date: 2023-09-28 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 688c84e40aa363..9781e2e6198063 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-27 +date: 2023-09-28 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 ac9cc0338f35fe..bdd5ae761633e5 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-27 +date: 2023-09-28 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 b60626798977cc..b972f26d53fd99 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-27 +date: 2023-09-28 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 af2135ccfcaf75..f469f093223bd1 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-27 +date: 2023-09-28 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 757e7215310eb9..8e828de602d64b 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-27 +date: 2023-09-28 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 f86ef3a3d878a1..cd14617fdec7f3 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-27 +date: 2023-09-28 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 5a50700863979f..36a72da7410e07 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-27 +date: 2023-09-28 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 89c1765d8c65f3..76b8ca25f50b5c 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-27 +date: 2023-09-28 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 a2f19223b80a86..178fb946707a75 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-27 +date: 2023-09-28 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 53365227f427c7..1b83537191f215 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -183,8 +183,18 @@ "\nProvides a URL to ML plugin page\nTODO remove basePath parameter" ], "signature": [ - "(ml: { locator: ", - "MlLocator", + "(ml: { locator?: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "MlLocatorParams", + "> | undefined; elasticModels?: ", + "ElasticModels", " | undefined; } | undefined, basePath: string | undefined, params: ", "MlLocatorParams", ", dependencies?: React.DependencyList | undefined) => string" @@ -201,8 +211,18 @@ "label": "ml", "description": [], "signature": [ - "{ locator: ", - "MlLocator", + "{ locator?: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "MlLocatorParams", + "> | undefined; elasticModels?: ", + "ElasticModels", " | undefined; } | undefined" ], "path": "x-pack/plugins/ml/public/locator/use_ml_href.ts", @@ -1033,24 +1053,6 @@ "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", @@ -1059,9 +1061,17 @@ "label": "MlPluginStart", "description": [], "signature": [ - "{ locator: ", - "MlLocator", - " | undefined; elasticModels: ", + "{ locator?: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "MlLocatorParams", + "> | undefined; elasticModels?: ", "ElasticModels", " | undefined; }" ], diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 26a245078de3ff..7500ed2c47a7eb 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; @@ -21,13 +21,10 @@ 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 | 33 | +| 150 | 3 | 64 | 32 | ## Client -### Setup - - ### Start diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 819f9ca32c504e..291bb72d31061d 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-27 +date: 2023-09-28 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 3a6fa6bddc91dd..844304f01844e9 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-27 +date: 2023-09-28 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 1b44a46e5975e5..414f2b16272031 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-27 +date: 2023-09-28 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 3ceab43574501d..1cd5f89d0c1733 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-27 +date: 2023-09-28 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 2a232ef347c545..4ec525a2ec9363 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-27 +date: 2023-09-28 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 edd59f5b7cd02a..107420ea385ed9 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-27 +date: 2023-09-28 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 d39114b7d63bb5..87179ca428b7df 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index f7af2bdf4e8ccc..a0db24e96fce2e 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-27 +date: 2023-09-28 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 3c160b04f3a6b6..2f938cef67d2d7 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-27 +date: 2023-09-28 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 744e090e99b997..f6704135387e0d 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 5cbe15c8c43b6a..dc78585ca3eaf6 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 5981f286ef712b..cfe2bee7e2387c 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-27 +date: 2023-09-28 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 3508ef25f48b2f..12a11dfc21a7a6 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-27 +date: 2023-09-28 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 73f6b5f2567f0e..aedae05cb938b4 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-27 +date: 2023-09-28 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 | |--------------|----------|------------------------| -| 693 | 585 | 42 | +| 695 | 587 | 42 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 75009 | 223 | 63975 | 1546 | +| 75054 | 223 | 63991 | 1543 | ## Plugin Directory @@ -30,7 +30,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 269 | 0 | 263 | 31 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 17 | 1 | 15 | 2 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 66 | 1 | 4 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 772 | 1 | 741 | 51 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 773 | 1 | 742 | 50 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 29 | 0 | 29 | 119 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 9 | 0 | 9 | 0 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Asset manager plugin for entity assets (inventory, topology, etc) | 2 | 0 | 2 | 0 | @@ -68,7 +68,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Server APIs for the Elastic AI Assistant | 4 | 0 | 2 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 535 | 1 | 435 | 7 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 536 | 1 | 436 | 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. | 5 | 0 | 5 | 0 | @@ -108,7 +108,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 3 | 0 | 3 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 197 | 0 | 192 | 3 | -| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 42 | 0 | 39 | 11 | +| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 41 | 0 | 38 | 11 | | ingestPipelines | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 123 | 2 | 96 | 4 | @@ -118,7 +118,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | 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 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 617 | 0 | 520 | 61 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 622 | 0 | 524 | 60 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 8 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 10 | @@ -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 | 33 | +| | [@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/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 | @@ -185,11 +185,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 240 | 1 | 196 | 17 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [@elastic/kibana-localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 577 | 1 | 551 | 52 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 578 | 1 | 552 | 52 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 145 | 0 | 103 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 206 | 0 | 140 | 9 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 13 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 53 | 0 | 23 | 2 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 55 | 0 | 23 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 148 | 2 | 110 | 22 | | upgradeAssistant | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/uptime](https://github.com/orgs/elastic/teams/uptime) | This plugin visualizes data from Heartbeat, and integrates with other Observability solutions. | 1 | 0 | 1 | 0 | @@ -276,7 +276,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 16 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 166 | 0 | 66 | 1 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 170 | 0 | 68 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 8 | 0 | @@ -491,9 +491,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 96 | 2 | 61 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 206 | 3 | 1 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 37 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 12 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 152 | 1 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 141 | 0 | 5 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 49 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 48 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 11 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 4 | 8 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 11 | 0 | 0 | 0 | @@ -534,9 +535,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 6 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 73 | 0 | 65 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. | 18 | 0 | 5 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 2 | 8 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 16 | 0 | 16 | 1 | -| | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 110 | 0 | 107 | 0 | +| | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 111 | 0 | 108 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 68 | 0 | 68 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 1678 | 0 | 1678 | 0 | @@ -579,7 +581,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 28 | 0 | 10 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 28 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 46 | 0 | 37 | 4 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 47 | 0 | 38 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 5 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | @@ -630,7 +632,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 93 | 0 | 42 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 10 | 0 | 7 | 6 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 303 | 0 | 276 | 9 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 304 | 0 | 277 | 9 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 4 | 0 | 0 | 0 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 3 | 0 | 2 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 80 | 0 | 21 | 2 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 791f9b3b4f2a4a..a7df5dbbdc9b7a 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 9410922b057ccd..da15a17a8701d8 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 7947dfe27f5f8c..cf17673b30abcc 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index fcc76a685f0520..b901f9a36a529b 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-27 +date: 2023-09-28 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 2b970580b02ab6..f8cb1dfda797d0 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-27 +date: 2023-09-28 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 8d6008e6384ebe..7b76a4472eb3da 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-27 +date: 2023-09-28 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 5c125651e82b75..dc821f68e97161 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-27 +date: 2023-09-28 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 b36b693fca08be..eabf54d9a09789 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-27 +date: 2023-09-28 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 9f57802b6ae107..40a29c00deff5b 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-27 +date: 2023-09-28 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 29c0562a764968..829153060eae14 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-27 +date: 2023-09-28 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 14c68fed21844f..26a7be94eb550d 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-27 +date: 2023-09-28 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 2047ad21430fd2..9ce73f3b3d1e19 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-27 +date: 2023-09-28 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 23b14aad816fc3..b8d0a2b0523bb9 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-27 +date: 2023-09-28 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 60911c7f32c65e..7f8b2df03ff0c9 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-27 +date: 2023-09-28 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 615dfe4d73c3a9..e979a313e34590 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-27 +date: 2023-09-28 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 b53a5a29a32ef6..3ce1dc31cc8d3c 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-27 +date: 2023-09-28 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 f17c24e21b966c..a195c2e74f5521 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-27 +date: 2023-09-28 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 ed04a04d8be823..fd4ffa31ac7972 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-27 +date: 2023-09-28 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 a33f35f1acf573..ff3e12a9e76965 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-27 +date: 2023-09-28 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 76f719cd709890..d41c0031245760 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-27 +date: 2023-09-28 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 a2f09274f67f64..20ec34b2ba72b0 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-27 +date: 2023-09-28 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 ff25a06f6415a0..8138b0b7690b9c 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-27 +date: 2023-09-28 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 fa845f8af50f82..8eadcba48fa53d 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-27 +date: 2023-09-28 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 440269f83ad9b8..282f63bb82d95a 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-27 +date: 2023-09-28 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 59300742f12fc7..48f9f39124c931 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-27 +date: 2023-09-28 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 77ecc0baa4b99a..e2c8c04a3183b6 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-27 +date: 2023-09-28 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 27a90cbded66ac..3d0b490839d7ee 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-27 +date: 2023-09-28 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 ac2f75dd7a96ac..4f00f67a10b975 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-27 +date: 2023-09-28 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 8f159ced0ce760..a119bc016e8821 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-27 +date: 2023-09-28 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 ef3037033a3ae8..2001d0871d766f 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-27 +date: 2023-09-28 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 84f1bc29113c74..dd882dccdfcb77 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-27 +date: 2023-09-28 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 b5c292a9be03ba..5a7744abb7f3d4 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-27 +date: 2023-09-28 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 5b329e76140d8a..ba4840e76be517 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-27 +date: 2023-09-28 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 52dc85ee981cd4..086eea00a7048a 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-27 +date: 2023-09-28 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 563a67a77822ec..8bed3a38d9d986 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-27 +date: 2023-09-28 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 24dd5e08c8343a..47d5a58321822c 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-27 +date: 2023-09-28 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 190a31ae3d43f7..797ddd54466a25 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-27 +date: 2023-09-28 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 700bc8d8b59bfb..822955b338e951 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 389ff0f130e26e..8847c1ad011d38 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -3080,6 +3080,17 @@ "path": "x-pack/plugins/alerting/common/alert_summary.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.AlertStatus.tracked", + "type": "boolean", + "tags": [], + "label": "tracked", + "description": [], + "path": "x-pack/plugins/alerting/common/alert_summary.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index a5b984a43b6113..a0be9324233af7 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 577 | 1 | 551 | 52 | +| 578 | 1 | 552 | 52 | ## Client diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index cc11ce629e9bde..ccd0ffdd8d18fb 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-27 +date: 2023-09-28 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 b532bc93621ccd..4724b1d9fb6b19 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-27 +date: 2023-09-28 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 faf4b23b3d9fee..89a392e85cd44e 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.devdocs.json b/api_docs/unified_histogram.devdocs.json index 4288127fabc2b6..de6f277f87c70d 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -468,7 +468,7 @@ }, " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", - ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"resizeRef\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\"> & React.RefAttributes<", + ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\"> & React.RefAttributes<", { "pluginId": "unifiedHistogram", "scope": "public", @@ -554,6 +554,31 @@ "path": "src/plugins/unified_histogram/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "unifiedHistogram", + "id": "def-public.UnifiedHistogramChartLoadEvent.embeddableOutput$", + "type": "Object", + "tags": [], + "label": "embeddableOutput$", + "description": [ + "\nObservable of the lens embeddable output" + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensEmbeddableOutput", + "text": "LensEmbeddableOutput" + }, + "> | undefined" + ], + "path": "src/plugins/unified_histogram/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -894,21 +919,46 @@ }, { "parentPluginId": "unifiedHistogram", - "id": "def-public.UnifiedHistogramState.lensTablesAdapter", + "id": "def-public.UnifiedHistogramState.lensAdapters", "type": "Object", "tags": [], - "label": "lensTablesAdapter", + "label": "lensAdapters", "description": [ - "\nThe current Lens request table" + "\nThe current Lens adapters" ], "signature": [ - "Record | undefined" + ], + "path": "src/plugins/unified_histogram/public/container/services/state_service.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "unifiedHistogram", + "id": "def-public.UnifiedHistogramState.lensEmbeddableOutput$", + "type": "Object", + "tags": [], + "label": "lensEmbeddableOutput$", + "description": [ + "\nLens embeddable output observable" + ], + "signature": [ + "Observable", + "<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensEmbeddableOutput", + "text": "LensEmbeddableOutput" }, "> | undefined" ], @@ -1178,7 +1228,7 @@ }, " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", - ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"resizeRef\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\">" + ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\">" ], "path": "src/plugins/unified_histogram/public/container/container.tsx", "deprecated": false, diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 14319346a7eb53..47af58f3b1b0ae 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 53 | 0 | 23 | 2 | +| 55 | 0 | 23 | 2 | ## Client diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 2b7f06029b40c6..3520229eed82cc 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-27 +date: 2023-09-28 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 fb3330c1361a60..1d359ea6d6ff1f 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-27 +date: 2023-09-28 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 9c5a16baca248d..1fc2ae6dba4e3d 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-27 +date: 2023-09-28 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 8b211dbf99cbb8..5db01f521053b6 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-27 +date: 2023-09-28 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 4debc821f93bb9..5fce49ae6bd224 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-27 +date: 2023-09-28 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 84583a6deca755..4bd53cf271676a 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-27 +date: 2023-09-28 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 6a368ddec6b396..3ae101e66ad18a 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-27 +date: 2023-09-28 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 dd5f73b06abe05..e3f8832deeed8d 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-27 +date: 2023-09-28 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 701b599ae799d8..0e9b968bcacbd5 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-27 +date: 2023-09-28 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 b366f8dbd26aae..74b27d1c846cd3 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-27 +date: 2023-09-28 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 0844a32fd547a8..bc6949ec4ca446 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-27 +date: 2023-09-28 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 029cfb8069ef50..009837c964dddd 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-27 +date: 2023-09-28 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 747207bf1322a4..81a64d33441621 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-27 +date: 2023-09-28 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 030fa0683409da..1ad872a67511ff 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-27 +date: 2023-09-28 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 40e8a2004914d1..8fe84f20eb7c54 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-27 +date: 2023-09-28 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 34a87031ad777d..9c678aca9289b9 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-27 +date: 2023-09-28 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 d13512e36d7687..709b8ba6fc23ac 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-27 +date: 2023-09-28 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; From ba31c76f31336e27a4fef5db7edb646ae27333d2 Mon Sep 17 00:00:00 2001 From: Panagiota Mitsopoulou Date: Thu, 28 Sep 2023 07:22:51 +0200 Subject: [PATCH 22/22] [AO] use toMountPoint from react-kibana-mount for header menu portal (#167126) Fixes https://github.com/elastic/kibana/issues/164366 ### Acceptance Criteria - use `toMountPoint` from `@kbn/react-kibana-mount` for [kibana/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx](https://github.com/elastic/kibana/blob/fcf838e1f389cae6fcaeb9f7bce713123a01c939/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx#L10) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/header_menu/header_menu_portal.tsx | 11 +++++++---- x-pack/plugins/observability/tsconfig.json | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx index e6359e8c5c7439..bdd14979f69b31 100644 --- a/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx +++ b/x-pack/plugins/observability/public/pages/overview/components/header_menu/header_menu_portal.tsx @@ -7,9 +7,9 @@ import React, { ReactNode, useEffect, useMemo } from 'react'; import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { AppMountParameters } from '@kbn/core/public'; - +import { useKibana } from '../../../../utils/kibana_react'; export interface HeaderMenuPortalProps { children: ReactNode; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; @@ -22,11 +22,14 @@ export default function HeaderMenuPortal({ setHeaderActionMenu, theme$, }: HeaderMenuPortalProps) { + const { i18n } = useKibana().services; const portalNode = useMemo(() => createHtmlPortalNode(), []); useEffect(() => { setHeaderActionMenu((element) => { - const mount = toMountPoint(, { theme$ }); + const mount = toMountPoint(, { + ...{ theme: { theme$ }, i18n }, + }); return mount(element); }); @@ -34,7 +37,7 @@ export default function HeaderMenuPortal({ portalNode.unmount(); setHeaderActionMenu(undefined); }; - }, [portalNode, setHeaderActionMenu, theme$]); + }, [portalNode, setHeaderActionMenu, i18n, theme$]); return {children}; } diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index 74a54afe8b53bd..2b7a9e0749650c 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -87,6 +87,7 @@ "@kbn/aiops-plugin", "@kbn/content-management-plugin", "@kbn/deeplinks-observability", + "@kbn/react-kibana-mount", "@kbn/react-kibana-context-theme" ], "exclude": [

*%;niR&;=Y;u=&q=jm^~(C&BibpgnzeNW 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 z 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 T?#YS)|IV3M{aSYB+He00+65E% literal 0 HcmV?d00001 diff --git a/docs/management/connectors/images/gen-ai-connector.png b/docs/management/connectors/images/gen-ai-connector.png index 4c737414d4e728216fa4f3b67c0041552514e3ef..bbb59c25b909cbb08e6632223938ae1f911016a9 100644 GIT binary patch literal 265510 zcma%j2RK|^*R~K0qD2ryj~2a$(W1AIkmx1aAfiNXLqt!aMDM*sbTdqJiKwIZPNFl2 z-uaKGyyg4;FAvu>=9oGAoU`{{d+mGO>s~^is43v%QsSbaq2Vhj%4(pYfuzyUu=qe& zz$d&G<66Mm4JQo+X|$4_d#k`7aTYpCkjIbF9stK6w3|05(J-%00bUX}sQz^ z#^M9cLwlqtqof49YnnM)SlBsP**lYEE%^c;;5aDiI-#MFF9@Q`k9Wi z&SOIJjmwRn z%ihtFn^#0cgqw$tn~#qZID^y4!_L{nozu>V@z0C=eH~c~Co@ND2WM-0JG!gunwZ+V zIEyndT;1qjKYu=_g}e2??_}rnSGRx;a$kMJ&CA8Z{jX~SO~tN06@6muZt+T2*4h>r zGvFQ)yn+vf#QtdTzrOnSE&rpb&cB=T@$w4%XVd@q>VGzU?quO8V{Z%G)LG)+6ZTi* z|NQc=hGN`TegBWK_;aBD_!Jmv30yJmf6bZ%F6DE|IA9|0S<9+F1Kt6XyZXVP0DiIl z`3@Z4_;G*wXmne)@8O}zrtSP&oP%L>@Mm%@U&%-@iAfJ3tnIgN z#@6Sv$`FlbFfcrTVK^{+k)wFaK*#lrh*WpeZ~nZnDVZhG!7gcGrV5eUGJEX307*;n zj!qs)W9d~|nX2A3D({@B_gc&hrWsJeMF-KnLHoyFPv~wA3=G_7V^dO&VWkhmBaaIx zF|3{NBbqo-ie@GaiO%?Vt?Rsb!wgk?{5Uoy<_?=~MGk7FUjKHD%lZX&mFQc;srCDM zf)B3w7|*2UshzDpyd!0wkTJW%rXhP?zMVybTzG4mZ4RYaEHsleYWo| z<;~1MDG)6$8U1x;RjPqhQAGuYK~Erg=D_ysQ{?@{$s)dSbjvu2Q~dX|7cuS z_VbloL=;P-v8!%88)Ln(x!o`+Xp~c*Y@jjdh9U_m(a)EzOQF z>}in>FEIW@engl*vijw(HR$ae85HyynwlF@AZp5Hf`FCj+C!u1XWHS^V4+d#lF1vB21F|m2Oi*um0R}G)UKMfg>$0iOOag5X`uN*(M1L1m6hKCKKLCqsK3^2 zt6r;o^fu_L?b~ZDH%vLee*zPRk_yR^d$0VFLGJ!noPfUA`PMLY)@5n%^&aC!{|BOu zjt-3qbEW<EM0YWFK> zujO#>(A~g)p#wXB7CeX5sHXBs=ySTQS=nQ1-uoaGQtx%BEH58)wIi6CW&!?K=eFnJ zW_`R=$SXs2SLtgk#|$aFhkm!lae~@A8n$HzGkFDwr1_=C{D|s3_bbrvA565-G0KV+ z6kKOv`kiq{roIV6p`xj7Q*K2jCA|c^3@~5g^d(UFlV0iE zo^M;W@Onsgt>Ir_^edAJE_1=&y_1s3%V!ZlNA&ZB5m|WHbvklE^b61Zmwp_rUST-_ zu!w+uY-IAjyTc|eA9ChkVuf*?M>tk$y5-&HTC988F!Wj1Fi)++nDMa{-S@NO-CXHF z+$;bP+`o^)3mAi0Mr?HS-928d%Hq6^Pq`;{gXONYek83w-8~9wO2#YT82dnuF2MiW z^-zs0?wtTBP&bIzenyPVxS{S2w~@CooosKKc=4jw28^Cjc0ta9;2M6)?=tHR$<53} zI{3n9CNJDJiI@RcG63FUzCy7#(dlCXujgtWyuf+{tdSY{ZT&c7IDm!$pVLezX@E=m zK$cF{rBT?-#;wtNe?+>y3JXg~%bcdD!sY8PTne{{xVW*F>SN1LdS{koQT2RN9PM zfXj}%vU?8aBvjB*t??{sL;7rec%Pb|Wc?j2>|(PH8F zominME&_AL%f7g7ce6H=ljCVt0Ni?-&pA0G78zF@NhopF=jL*bx89*^nYvmV9{7(g z>Ix*L5@$Ut(6|-$b%V&)Z>!-{jZAF+gV^?h>Ug=CWf%6B#U{F ztUdr_?P`H5i=q2J&p1{UoK(;8>vXIfu+|_vQAtZwSIZ0?|QeXy|QX&=q7$ zeE8aw?6axn%>$gX^TS!bS4WB-j;%#sB2%0PLU$JC2Xi!XqvthfV;59kEES3HIrNG1 zK6hMW%WsboHVU`acVa}RSH;gGWb(TL41o)Cmg8$~TJ1P2G2j@rM5o`v_MK-^r)K|! z-U!TrO^`vow1wWO%=hA0!LA`U5Sa6|FX@ALy^@@QFP}wt)jvxR^rNzS$xx_W8tRch zY7FH?+E)$-o(_8I)nJn6JC1sG)=9V-NPq?GzE5(EBN7>u_; z9}72wUoA3j(Q*>1Cnm8kYnK@4>h7E%H9kKpFepe@&c^eGxfG^oFMnI1qSW6*^*{F9 zM?pA3C6wr7of)fG6VPu;-|1SHFZ_)OWW2!nH*(a8=k%>|J>EeqEm@EivD^(~9KGD$Uw2OBtGw%5Bue>v9vZ5Z8t8u35>Zi;tgooG)nXB{J&|4$wn`YD zMs0vy>NK$kR;YFxuo;Pd4)#jKTOi|*RU4BQr&Svj-6y31vDG;S;}wo)+il2k%Tai# zez|FjsRUsozT~NQHiu!2YL)%03AI@=YV5c;22Rtoh)jQR>86~k?6{gst^z>z+0Deb zRTq!dMQwi0QOxC3ukdL*%SGk&G=rTbjq#ms;e%spr>=g-B?`-S>-@EFl`6(Rn#v^?_4@q1l%8TB&K{IE1 zB^%o%QZBry_nQ)$WM(JM$iSlg;~84Tlp4!*PO0Nf>h(gUjSaGU<9UZA7l)^`zB-3n z+au8DGYtr?y0VfK&rUW!7kBNPJd1X9$#az9D{*9a6a*nqnQrWRd5-8xzKki-+Yf(L zktP|4M;djXy>DaF@4VPqbCG`oiT>Mlj=+RVGBYyD0Hg>?0`V;nPenR{M!aazJfPk7 zOs4oE4>9$CU90GpSTVMISR@%j2+zR2q%RyHN^Zc~czF?A{m|62rGiQ8rg}?=MN(Ln zUf2XNvMbSc_EjA4XrpTZ_t+y;Qz0dt0>!D`7}$F-@EKq6EuAvJx3YswK9YXml^H29 zBrhBGYhg)s&Vt)a%Ij5Gah)vUJuq2zd3ug#v6({QYH2a+gR$5WZ$$99)yPLbS<6*Q zdi!UK3}RPb#Ck`D&-24&*?rL=rQ{J#fVj;+*?7=K{wxm8y?@k)Bm85xIAZj=yT{FEJzJJnjtP}uggH;&V;@^Q8c^Sa>Z9DQTfR~E{E zov*>PO1(zVY{>3iLB}ufvdy*(6IFtP`cF47)x|_K2Z{(z%9j1jUeDu?Dk1Dr<@{AD zG%7sn;hSZr(&=F*AG*{+h3-XS=@)cN4Z#ysd&Kjr;MRj0CG|^dP3tH)>}yLra+yk4 z6h@rBK2j8w?sFlh2Y-w*ATqc|rtLrN&Ir?{d&2rUj@u`>iKpvXp)3aRYQP>j|y zS(Qab^~|P?85Fh%EQ%C&Q{_J9O~;Lxjq$<=4!yIeT8@!WJg!fSgld%bmeju{Sx|LA z%<8Y2G(DjVxZwf&LsjHn9i%5EZL#Nv=RP-%nEbjHCrbEx>6f({)ix(GvE4l}k^F=4 zo>wcDMgWPb5yi3XDXD#Af-tWd&FhqZarkUKhrl~_v_owPm`X)eeqsngF=0QL6UfO_J9P39BouwBu@9jA}G&k4AnDTmjwnWtKO6nyE zS)&Y5;B=}(IXg^g4v$^V>fMr_alYy+05O$-?Oh7PARz;l|EkVksB)!750+sd`u22z z7M%$3@B_^rxnjeO4t|3V{3|Z1P^5Cpl@A=_AdJN~W_xeedxZX|^ z`uVeU5LI{UZRy$hfYi~z{k6_b@md+!>mzFQU~&)7M?rTg2FBVnoIgb%OT~C@2D_#2 z4UKCcHjiDUKFm)3sDVyS>LGub9D2I#r}l10g}58=+a95G)!SR}xpu^{4eyrD-=gNz zv9ote-g^BFon91f&r)E$>Nm?ci(4E>X`b^{e#WtEvt>0xlI@UyV$)VFZmHI7odN23 z2%2Uw8bx{;FUZr$!k6tIn$2_ayK!%Q!^I2uvJi!J@Z{d3HhLlk#h}ICK+Q;U zbRgOsU(*~h*#bym@}I$TyeEYBIAE5&`{Mi?bH*^w*jRi9_Z93}>f*rpR`sZD5@yWe zxKbfsX1VudE~CLN12t3@W?3f9D(0;u5yzVa%_dV5Sz#Q8Ra0(IEwY!LCms|9iA9d< zb^KUBChU1?1R*lRe`;SNul(w+7nd4fgJ8HAJwF|ZHgpTf$##_;jhWaIE+u^^IoxH z&l?%+_tXx2+UC@?^7xfk;ADvf8Ex-AWtj0JV%IK-YJHrHoo+=oV#N~+Y1qbl2Mkw; zD-a51;gr+-#^@YX{xcaf0qw*Q_uMOs+af);|M@+%+U3=nc)(4)N^9~XNEyK?5BIdB zA_Ju#0h2>;?1A{FA|K1Z6bES$Hy1mXfwdbn$p;|@E{ltsomR(V`*o3bkP)WhN z3-Cd;*saD>`j;aiK2R^EQLa>mwT|N50oVG*14AW6#gK<-Zt~!eUXjw0n--o{t}2=o zU`R~;52=6EHjkCNU8c_}H!b5WOD155KLRoiIxeXZ+86jrxQO0|ZInMc(0s5|GXCiOZJEmOE=p@;QF?q0dK8n=89G>xI}*Nm+i1#L@C=OZK+ zhdM12-!tS@l4yY2*Nt_04NJb>gr4HZ2*=f}a`Cftp>TV4ic&_0wT-Q@g{-i5h7@Su zPx#eA_9r!}Ug<7BX-Mxc@fW%E2J7+ACl|XH%Qi)aGQeP2HGQ?t*WMOax6GWOt@m_^ z=P&AU5l=_NaluM;b%J*~5wlSXIrsB%YxyN6UfbCWDvQpz1XFkI9?tqADcM67)YyNq zpdO0C{Ry^T#OYwr>s8i0e>p0le{tA&*->RXY4PoQ2ShM255|A?K{J%Hb>1jN;Fz95 zoY^Td)F~xyLG*}PRWOo@IaN%sSR}}3yo2i z^hlUY79z2?8p+G+Vd=+-`hG;c5{M_FE(eVePw#F!-n9$j#LWoKS#L)C;y39Tr&Hjr z_Q75;7Q>nY9(6X;8ktj9$KE-=#ERG6+bxjlg6(dsIUL~JtwxNDk|drR&-&EN^b?i?oL`ch9>_^1LM#>l`!r!kd0Q$L#N#VHD z!6H&SmR^&N-pW$3DVgdy#Pc3g5*kYDbTru`d!HpVSP1Oxvt-)Y&=*qpp3iA zz3~8l7(x)1$(;s-p26gEPaX~dsFR&kT}<%TGv*JpoR5=_+!V1k;l3@K)3r<@i!n{z zdE%mSB@Ju1ZcwGP+?%91+a!)&9}X6cS8()h8n$St3wp)^?r7niIoqt$N8)Qkq|NDs^9zBv|q!3K&RKMdP#NnP1a#s z(r}@y>t2P`wERUZZiLUY(`CMDef5r4}30CPNBKI`tzNt}pGVbTcozx=Z zU)FV-lZe4(vn%9-@KS^7Z<99Ino_~7iWPh{Hjvlo^aM+>tQl?LBL&Ox1#}~tVM2S~ zn+YFBQI$yk!g2zpqR|Ait4bCrm1&>8uD_y}g=y^$yPweZI&Xcr@w*!RRu?#ZMtCGU zH6H7c6_4x_9IBf8sAA9JEnAzhNM>OL0>&3K%iF7(i|>%!{N$ln>M6Rpo-cxJvXkw~ zf^UV6b?`@1`4RP(=$58U=U7I}y&|T3mX#=W)+tAB$jYd23#KgxRvYD_&NZH$@fjXN z`W!EkBTFH3C$-r7@wJ<%xsnI~4E~ru%ynKJ*gRPJUfOu^z%qq2k?os7;|rtDLj_K0 zwXED*EoDv7I(*$6dV5*UUtrObu1??1dSq*jwrjXk<`ujkK^6fCJMGzgrVAKq&l4r; zb#3aX#CSZ5RDB%Yxs`)2yGN6Ao@7dIdh5^yU}ai2kz@X5?=)%(YgWqnPEaEP+t!z zaZrYvdCc0m9XLsBp~mFMxC|D$l3*q*z=m;Sa4OLtq>Z zjU3(hn7;*8b-bjL729f|mno*#%~OD|@+46wR5y<^ubk$tw}nBaoD=SGZhtXymE*mL zj+P4X+N5TVkmPMXRP>>suA`DivSubKhl?y(xgpA=LdsMb?J!k;>u0c)0Bn_$lcNaG z2RT4G89S&INHftHenfX4E1UC6sS`XK8L${Q8yWFqu;=oSQ!9AZVMxpQqG_^YdDBYO zd3{FZiWe7XZZ?a+f<#Tk~)6F zS)39wcVnPw!>NUg8aTy@owUo??E=`nZd`6E^+RZxR9+F5^!HsOl!JnTF8qioJ9j%7 zHJP99ygo5r!b3C4&d!MhNVtShich3NX||J9NRj1Xd_B(6`U)NAG2;9HOzH1@-@`Ns z(|-fn-$)tZ0nFIAA5k!^&zDqUaHc{8jh7%u8f?=J`ZyY&{eq^{DSmUO3)XuoBoP;` zbA{attSJWax87t7?{p}vUlDf>qY8L;$7&Ywz#E~p{=MJNv*nR8gzEdcj6n7lzrW~) zUL2=BJwm{KwboFKtf6t!P-Jt=Y~yoQ>S#WdM5G3j3Koq}k)}8Y(a$g@du61SEyj9x z$2<1YF9vy%2Z}F9tBFCx8%c>@S^V(do5;b@(saW4eZJkN5T21_RNt7WTo}(^uI0qR z3;1MI{F%e^hpwA`W9S!P__mGe4o>8=C~i4sUr`Z3`1NfiqNSU7%VLgz!-U*EFmw$+ z@0Gk%>{QAZfh9@|YFet)dy;=aHlx!+dOf8D@GyVBoFlG+9yYd)9=k2b6`3n(^!aR( znHpx)Rzmo|#B2t8BO944XwRe)&q+9CJ}I2cI3kC4_sDdfB`P7|Zh3?o1b|zM0Ce{x zpWJm>OJO+)s*8(d*H)U(>)u$MI-8TMQ0bDwT8vsIv6Gu4B{MtU%sByNQ z{R}Kk)5XtjIj^H34Q+#gCL1_Y9hP$NdBB0`Ew-O3Ae%MMFdVy1pCH7aVbFi$>t69# z&Vkn#SKgv^Ej5&bualOZezUe$L#N+M%UPtSsTepOb~GIY?R~ zdNj-c?HQx+)X;qg+O1z`H74*keu(%+HXuuhJyO6vQB^Brhp5NO*U*ES z$H@(mC-{^ncKLWNijgTXyxCiBFhf~zsTKA5cn9c;169h^?Ct7clbv?k$=M!Q$)oZ{ zAj70WuDD8aBjjv?dV`hzoTcU6BpYWW*4JG(pG&+ z``M4k1Pc%pMV^q4IN?`_K5e`RbhO#kM@?rLmby=qt5E@)ZGWY{y2qOJGDq~l13duG!(8Q>e~%Xo^dQJ(kUM>xWjwCKr*;c5%e*2q8}YAE6lpl>(EXFp(cKn z%=uoPl6bH&*%|4zS!L;azOOAZUqspSSv9@WI@qxHBHjg9EHrbr!FVDApE7nroy5%TWrJ`+ZC#316Uq(P%R0T@*lVw;6|E5N1BM(&D9x&mxZ^F{a_ zq>NXGw$>Y0q@e*U8daw zXyZiJ?l38kIKUihe*|1TW`TR+zmxD*UaUNw4XRU88%ylSc7N(yfv#T~0ge84axxgIMcS*oz-d>Pp>7 z*cDQHE92Tr-Nti8;YWJ}#zf@%yKWOtJQ&EU zaW{T>(j$uW)uHUxayk%M_F|hlE<^ihm4>LaW;(>D{W+3La#LE?;kV%{rXroV_%sb= zwobXJ#-}IrK$@qo66yAM!`_9jmtfW0m9i++1<0|)^7lTJQI6$eqLQ3trS(4gnCdsT z&Z(c$?Jc=qyl64<@W3J*%r$sobpxZue=}XkO-okFpTMK9z{#zjU@;@>(Y^JNIx}CT z6x$iS8r7s(%9J$UZ%6%E%WIsJ&ad?+4_t$8Y>B2yuI7+fjO&-y7G|Yt*J05Ak%oPV zX?-(xdtM&d{g^*Je)fQJD$9NnJ66=CCmM5CgTJ_^SSrMA#*kB3utsEXI|b7-)w0{0 zfk8(eT#_$&k#mc}GaaUz*DC@`kHI1zc8hPUJrS?o&db}ZbIZySr0K8wPz{K6k3*gl ziivs12GIT3&8#cOgArsAP2qir zR=pd3(36)ak&RC^RBF$?I+3gS-DeW971{bYNoj0%9{>!KiC$gQH~~C@3G)AU8rknH zL&mvRK|ukal_m&#L?`>G+VL2k3S?{Z4SW_WuXv2=k#A+MSF>FPlEMa@51$vNF@fED zSdektgeZ{f!8TGl^9Fw9%XAjcsSL;c=i2SXBRp7?Q)TN2!=0I=%AKF@xsd}FNPpLl z*qe>&dhmyRp;Q}nKLLH<=f_}=^L-}24It!o8KPI~O0A5R;AsDz{6p%n8<>;nS~sK| zxiQ&3jqO0r$DvO~-9BEIfpXkIkjlQf(BZA3kh`BPfZ#%-@lkW%{EAO^@-zoaS^~r6 z*={LRU6v|*px4RRRCn>1syJ$z1k{R;0PdHoqd zi7*H@f!|NJ`kl1~2Q_KfvX#F7JFK#2m3*VGCL0V}!yAk{W7y{HK2tb}x~?ttoIVER z42vUAxcBe#@;+^V^VyhpCDWdK7+fCIS1}3$?G1S11pFGbp!nSmdD9OL7x1#W)eZXE zcNg==yTx50pS}JzR~}hA0T}eOif?oc_r^zw?mXGplP zA5o&B&hJE&n6h+0Dz7u1n;S?n$1}*i;}MX*QEhizllXUXC1=y}m z?5K~iCyT>ZOI0lnSb5B`>fm9wSs8I6Y4wx(!x6pSXs~o}=5`A&*~_NKYg36=;-9-J zj4Zo54OZi8Reki1DRHYj5>Crq4v^_yAXlt<1&$kLDq0NVhC@pXMfDz$i5IadUM>U3 zO_$Wd>o-}&c5Wb4k;b4GAZa|py2bUVjmqqowzOcVCC`Pn-FqiPdP|;8Y3X! z!4XddFsr=Y)PzBjknMd+y2#kuHcd@eSZvNK7!xAVr?z>3K!k~)HNTn%!cstGVQ?R| zoFm^Il-c~idCfgopl&a!?*mDBTKqVHljp*DHU>ZKiUXsqy^XDX!%<6oE;P8d%aAc| zi%LQkNESRW)h*(eJl}&oE6`$h*j3@Orh`H5-8H&jicSxIBDQ?yYF%ODyJbce1tuoP4@QeJ`IEfl-yoW^$ zlgDdgE1^V>U9$Fs*CgmL!xg7rEiJu)Sj}~p7oPnlw$ANgWsWDSvAK`e;~dWcxe8FE z^G&F76kq{jL-2niK%`5*()o;2(8JaLtmQb~6Q$~paf8*5cs&kk>Lo)FcI#u4*`Fcd$QyI{b zxpwb0^qGmYz1|F~SPYNHT|~BRJUmtrZYb_YE3~h&i?s*9!mQqG`Av2+X+XykgJ{q{ zITszNvGdWrQ!)6i?hE%7vpEj1+2^l@Xj?sdSL+>sO}S;tTyVUm`?FaaVx+#ZnQ|xV zldVPxYCB7&I)+nUXsKq5=r@4@5ogp;`G&N!Q9oSiqUtY9LrVUGlTs|bvkN90W z<`4SqUesTe4Ce!^0Clv$bg`9k$B*bT)uub~pM{=2=%Q1efY_cI^b~IOl>NOcF`x9& zqw=B`Ab>64DIqDA{lD?pUwv}a1b9B6bVvn|kI7*$-lb#|t}Fm+V*=$z&y5}^{9}9E zfU9bbXP=$`(oXc(l~(4T(ENxp#ftv<&KD%;*4EbM0Y~ZvtCvkmw?W&qU)oa`egk6u zBrJ*KUTjWP|52-?90SxZuxb_cECbTDgETPxn4nR?n zzb>HsooW100LMxP%y1BvwAGc++VqPR<*$sdgfmUSR<%`)^_9+L7umn%VgDwGq&7iT zKZ5~5te4e?C?=IoAgR*qqJdZ5Iib=WH1kKXn*^bF69=H8k#>0 z3h&K0$=b+YH^Z+9$>plL&PC^*kOCU-2_pf zv=k`+hKNXmCiZVhF=F+-`XA+ZNbO8*@ay)x^5qF#E9kRUb9@B7P z8a;l|7Nq=p^Ce7cZRad&6t!FGAgyaXvR9M9k*Cv(kStm@7@v=bjqA31XPy4GqJPWx zj4eVfo!zU*_zf;O*L}mySB!uhhK;qm*KOnMB~r^{BW!VJKhAb%UR@HoIqkL3&ZvUi zZlh)=9}>}jIr{klFq@rj8$E?s^;PE8Mf#Va&@ZCPLyAuI$^LpFM5a4_* z!2;v0sZXb8@j_QRdFL&#>cz?WC2EjH-1N;omj&WWCiEWC|G#H2y_yC#HZ~2Q)Ui-K zg9j+^6QGhUxeO0c3^kN* zaol+*om@g)2FOdQ4PNV>_iYdi$42LgvC%@$61_alj1=E-}NZgz$SYH}^ex^hr zxwiSH7+H-DL>x%k9OI1I~rL z!3Tl1u8JjtTTe!3WKd|F;$IoVS((ff2;O;?P#W<4^b1C9?9B{$#W+g6KnhQqAAQ1} z#^g+zX5C-E&GGXskKf-5;=g@j$(8P&8ua?;NAM)~2GbSfUK^ZYKbZx*^%OqgerN_- zP|>YWVlsG!j|jzxbnxgeBvHBNFctRsz>5CZJhLRTvCn?kWE@``HREC@HFx0c+vaUO zTjtA%+1houlkJmPHOH=gg=!@3z)hg|boJ$;o&KcTnmz5@kfvIc#5CCa^aU`YllZJs z;ER3V%joTqU3vbVge#G6%)kgtZZ>aZ>ys{=zua&=4^x6F%tNg|@A7P&dv(Oi>N`Z( zz$?)J+R{RdJcAG{N`-uFZk0O|`|PYCw>rAcC5aV>33@fVUHpOaFyvIe!7lHS!im#m zS@XMzaorTee(D1OSbLyL?`y~%MK_)oVVWx@3 zN1fZo;CS9!-C}ghS8?kGBPwRS=4&=#I7g&eFbU{~m&au^-aKg&QK=`v{`+4S*y-)f z5j_>^nzK?{{ne?@BsLbB27PSC!F(*|6mHP5-Hz!MqQtv=rdj8$@H92$7F;{5u&?K} zijEq`eK0X#jFu$p6^%TgiO|gn`pcGhebj1lNuzX09V+VyiPk1bLh^P>UA1$rc(#l< zU`e{+5^Er18fwa)QEKF-01*H=#(|mvuM3u-){r>NZ})HE283uS)M3!22wDFM z#F9x^d;tmUyVF7~y5-gUFb)xx?s*`0ytm7ZT5{VO(o)u;xL+p+R@W*$mVyuN)^7Qh zX=}3@_w?|+_S+ZAb$xRZD?H<^FQnh>bkF6PwYBqk?9QNiV|#GAH!~oWs}>h)!x?!( zo&QYvBNq7x&PG6AjqlMmiwCr0vch8B^;m9J6fVm5Sx1+{*?42FZ;p_2B2DP&%qCoT z?^t10Z!}zwT66)pD}1&{97wq4^i&IOm@(-zzca6Vb>tjfq*K{CQ=BVkcVJ)Zs+;)I0~nXQB4>`&t|M2d=jI zf;e>-$wdd;#>Z(WxY*^J+t$}uzj%-$5v}zXk*=S{%DPUdgg%x!3n=C zznRsGG_vyxF&^((9^sjD=Zkn_pJ>dH-Vz;^SblZV`cZhoVFH%1z$fE21f@74-guHc z=k=n+e(o8L#q>s9?-Tqvo!U(qU3+mDK!ee)+F{;IeNytFwqEV*XufynMBg4cQVd?m zPxt+379pY>^&o|ASvQfYGu^@adsTVQ3anxMq6a#?JmWVl>njvYdhQ`HH`9O6Yc^eC zxSm`rgo5>ZZ0)O+rxAPBOCCFCi%-Q}+~e@_rdYSM-!YFRoSfv)rSo@S!VI;LT+#yy9kpsYepNtlC9z5 z`g_JpI*r3SsBhZl{VJ!THT6_04HKcfj$O?MpHYCyzHK-fwp?r9;Te&+d(w8{h2;$M zXFMCh=1jJ%-#%Nr5KcSY`y$i&*t4s<-j*nUiO zj$vV*t3qb=RN@F4CRD~4d=GF{)HQB)?5n%vHKQ%6$jkC!C5i3KwvB1Ka*aY`QjKy*}9^Q)*yJ7V)zHE2xj0{~bF!=i;GKx02bH{XJRO`8`CBk2kg9 zyA{TzwNo!Z8{XblYpRWpH!M77k~Z$^b*PE26`A#5rxw!ick$^ZJ387Y9nO?}6}Q+s zDsWv+KTPlx7lqq$0jTm3t{ndIJ3Xl#z5hx9-(Y~ip>ohnQotvH zN;Mm~cbqHNh-A~6`_QnxsV$Ho->6CXVqV+Pk+yYmvtZdMCf>*cX_tq!m|~Bq?Xu|+ z0gdp&KkI4n$g^qcJbLPOYJ0negXOT`*ucughLL?`#RWlPNa*=)AGKv;7+ge#-!!y$z7?^ljOSVgcM|E4-zazz~6lqvo z96m8PEt4oY=^R3Seryu==v-9)&<@kB|7U!BJAZE@s>h3ks|r1ja@rx68op#mF4Q=M z+mIx3$mSKT6Xfo&HeiW5!p@(BQFisg);D?{oa!!}-Rq;np;iVc-Sc-4q1ExqdaJTD z18VDJ1cuStL6(G^OcZhBu z>dL(WD~@;J#>B*2+;d~J_xe8~dA~aHKA+?dA8r-slxOW9{%S@^co$rCqoL<_=By25^WpcE=IOz+z9M_Ax!UOH+H#t4jPETttPE!{*A6Y(<2p1 zabO)d#Yx+#$)S3bedA<2rgZ$O{(B~sn6g>#Q39s?5BDY%1Sa3;rbvER=R2SO;`)l5 zJ-t)_}AK#ltUOdb9> zYBZT`pX^(2k$kG)+YNDWYvfYnH$4#mKcmK&etNlL{Qa{rxW7lTG|n&{a{mec;PYU? zevj@aKkjTeH~8wzs_F`KsS#T0*BgZf({38c;N!B|8Di`YTsVR#sYR2Busz>=iBcJ`p& z(1ZuSUK_{OSY~d$7%Ck#WCjuLtJ$9cYUN^}C6HfF;KJel6S2`=gLQ{{K7$9JECY8e zHnysa2=iBVUTa}{!Bwey4o(VWC|CNh^h&CCZdYF<1synZT&h;QRggG2;`bVynFhC8 zYrTmet8W0}?m>uQ$p*W2)rVC2mbzf);}H7#V#IpHNH>GB+SM+%zXI-p%3IF``>;TC zW=WtV`YQQgy+Ew21prC?v8H&_O*{#5i$c0P^V4FAKM+Moq^)74TeHAjjG81sw0Ua)fderYP z2lIEu8QFKUmUZLW3H0jv-*gF~66c031kci@93(u_PZ~FC&)7Wp+~B{7;D52As?%qs zhC#pSHTUS$4JTjx1g7n;SYehPX!^>HF;cTni;S^`ZEOheC}ISp{5)&OZ`;O_Ua9ACUXVRBaG`}l;yHAugd8?y z>Vr@84$HB?Nlf{TREaLU|Hr?`z}Eh^w%}kkmT+7uB!dpbf7Dd_xX6zPLfy}me|UFh zqp}3}7XiAL&ksx9B^+Xz-K-Qe%{NHmojn+mv07fL)HZxj*;@i}F^COW{WOCp5PS?x zCVN~&&!#+ix=veVnJZz7NmK+|K1Zhj78DqJNO)e*rC}HQfUr3H2{d|k^;y63PtSY# zRxEyyY==%4ZDDxOw}-ta^T!QNeUjmlJe$M_|ECD#OS*vY*b-_-wf>&tB*C7j=3>SB zoJo3~SHUzv;nU_*-PNK9N1=!lYu8U}t)fLTg-gQK%X7~%{BZn(!(Dn8CknYfBDt#j zppzP4M`raz6HCWFsKEOGER2V8r3#I;TW*J=nHWhzHLcwhnW=3P$94V6$c>mOP=Nb! zWp2e>V#@(NoUv9R-ZjcR=cVs{*dpIn0Xb@a!X%4YvS)uNa4=2LWmaND?MXM~59c!L z{2$`YZMDmvbP3>2Qyd%M4VC=TME(;UYScJq`4G%udmSKnv^QjqELi&JWof(|jq^+F z1Tx$dL^=k)l8iK@%p}ivZB0!KZ_wX`XREyT@oiO0T5@$3s>?|es9#+xW0osQj=uOH z9`k`~ui*x5d1mj2#5|+fp;6(3%7oOR9=rYG%x8A>i&%%%nW<3`0E;tOI%$=!>x&%W z5UD4ex6Yrf?kAzCOwON0a=BHO=es1}LVc`p)+0yvMQ{SzSD`Om^Iq!1=k+nXQluDx zlwnqHA=gMGfoFYp_$WZajjm-hvJCDNjWl+3#_-tq=H1-rqJ3>oE1VqR5fND37DfEc zI{xBS&DzfUsTb&$)dY#WFHv_aM+n+KYb`n-Cg$n#?pbD#Ol8}D*Ou5YcRRHr!Pum* z#l~Lc*YKxENiXg{7~KDVjD2-jRBgX50uqu+H;5=mGjyj2Qi`I0gd*KF^`T!9BCB}gj47pVcjfadOS zf6J6o`XS@#?BI7{+~g)L0{nSKF6Jc5w>|2kdst(~(v!l&@u^U~Ebq0^R@iyGK!UsGWV!G?bU5CU=+uq*yGrs(%? zvNa@`;eU~Isa@1Sei5nqf_Qmbq+YkOe4?g(Zb`&dY`&}%7J}JxI3k`E9$Rou_fcv& zed!!kTk6}JUKEQsJ)oK&Ev7xLF44IzE9q%4s05a?n%D%N))d*?-=W`L8dMr{+yyU4 z2Q!X)CqMUs&I~P?WJdGa+{rviYH<;t-PrQN7jzgcyy-I+wUG$n0yHPr`SUg!znlZw1vtf|#F)v@(yin|cKv zwi|UmeDW2v+c+g5)}+Al057ywujRz<@a)CaQm@*%Js)j@_o4Z1<5epr;+#ua(Af;L z+@O_%IdQZCo1!W*+T=NcYGs1?;J8FUr9A{wZyHxBBLZZ-+CXNk-} znlF7&Z_UwGFpQT)8flq5U3k{)ny~9U#X8isQ%)^S$mJ$6X5eSe4i+Z5L%qKE{%wk2+f-0wPp^s|t>pp^OC5`1b+H5gFWpZ#HP z+~UHP;}P1rsi6Au9Kdh{K)mAqD-{aQOn@$&O!q?|4sQe!rLZdgKay_l#T5PViZ+1 z%(by?;2|}k^n&QRU1v@H$ylycgJVHNlA;3Yy&-?5oqoWDXeI4WIqDy*W#+>Jj36<`l$>v%&##3a<(Gk%Nv)lLHzXwRz)f#Q%Sg^pGdk#g^Qr&W*#S=c($4e(tX z$*>13BZ)xW&&t&W*wgsi;=`2MEiZ`zQZom4>!=p3ZEd6n&^7rPQUu*zcGuZnsz=!< z56*L*X@d#47TjTJnMM9o>rEerUlI*appfmSS;;;z?kjT^iyxK~c#M*5)UMt5RPG+jNnoOA;KVA!`u8FKc>CKZxCjt*~RCp-JH>6`rf zyOqy(Mn<8SU~#33akdo+Il8$C-vJMrmQ-EZ=Q}iyReL1U#czhF*ZW!?$42RKg&6E z?EGd!x(l}Si`&kWGAxR)2JN5<_GNE{ggI*)&Pa^fb>u+{mzMvYwUQ6WnBzYpIL~81y6$=(Coh{!#S{bs3jz zxXCe-CneT|n3#kEPkdIS7?*0uMiJ!(fOXs)5fFK!t~A-3eK zD4p|^q&Cdl^ep#bK}S43Yp+SE$YU9Wc-`(ezVWnJE2o!j)G+Ec>~G=~ZrV#~dQj#v z_MWvM%Sk_d9Q&Mqvv1qkg|gVFa@KB)MUa_1U*&}fRWZI-{S`}`oYR=s55SAX96k^B3`3YK`pwjxu zTqWrt=9`|TQAo5{A39(T9p)*#hE9%Clpd04N>NEemq+U-U)?3&@_= zgFd|xDl_}~MPf_MGqWmcKdBDH(PP`bwC4dNt*CsJU`8LQ^4kZ3Kjq-42kXv6s)1Hl zImuaMy5__S)q09Ld+&b81mK(t_9AbZ6>zDC5kVC6BzJ)zQe+sDe&{-VUP8_!+WMS! zxax$yahPjm{M%YdZ+*=iCt>CAEvLqV2=+`KVATC*DY*M5c8k(0Qxr*g#13+r>%F}L zWZhfyav8LfD?$Fj>rDo$jcHId62O*z9}*^c2cHE$@L$~m8j+U_WWostDn4QA_>;Dx*^g^@sin;{SL{jZ#&SFKZ=EordR6iS1aJc=$I%Twc9f3I!Q zi!SqPDr?%ff!wr0zryY3Nc==B;nZeQ)MRCptTMJ=onL*T; zj@mtYw^YTRDm$WREh`k_I1xqdyoygoUNh}T0evc&J_4{6b5wjbI4%hrbD zbbKg_p%vVn@=pC}Z8uWeDAsrAxx)|K!R|_-K}b*3n=Qi4pNl@+wa`BR>Xe(Qf!-Rx zL84}5N3^Xb#2qH}>^qB&rTJA?PE{iUu8<1lHPIijjx{O;P1`%AJ{x;krd7&ht_pq% zWo@_Cq_?L;KeY$$kFAsRX{R>^b5fnQ)fw9waE8e&g9c3fsFGZFS_gQU}m0Pj=CX8<7J$c`uY;*57u)iw|F{{zH zLjzdC0ZQ7IXl@jg;I^03NgE~qM(LN3#FC zP0VdgE7kSLKO)Xuf6De|0meoElf^Cx2U6xvPa^_(peil+Ai2d6=G{pt2qZ+ZR^UgD zot7=;K9keOxI892Sub|WvY~lU73gV{pYzsL(Q_-n_LYMwr+!WlidI^sU|;>0ol6_- zdt5miG>jvP1BhTw+g%gUVxV8`J_L^Qnnn?4pKxq@rzhz-`b&na!gGfKr}YUk|p~+i_rT)9D8OWzQKlR(ak=VI=bNYsGT3WioqOqHQs6_xg91C7=)1N? zN$Sb1B3IS zGo8=o+fZFhcb6ohyJ)-{ciW5us=6kWVww@;kj` z+Ij+)5Nbp$#39iLWA!|E*t{u0trzN-kzE9zs(qg}+P^nz#E^!027q^iY!BgIKVKHD zbJ8gZ@BG}W)CG|vfN*#2qGMAidE-fcRY4xkGg_ioLqH8`r!e)c*=@Jk_CZzl)&07a zepWQ5w{ebQWBkL4Zkd!%Op2u3uR~S|{xJGgETlXr*p1nq61gZ4b>s&|eDTnP6HI>d z!UAc8bmwT!3$I90oIZg>@0Mm7lWJ&p)z5$JOQ4$Nue1*NtO2siFssy7cQYOs5L7{u z?whB`gCosci!V|z_TXTtcZbiM{@Bg=f2_|VIa1=`0K4k5a%G^@EB@>UOL2A&F#gqT z(rnINiO<~F-nI7I3?+qjPC!aF2=Ll*+hKhLgOSV?$``|rR%g;Yrugo>F>=o5Ybmj& zk-2CzIXdbyU62I<#YH&@_ou zFI!gA;kue%JGXeHTBL%!6_0=EIIbm99Nk5@{nmw|YU6}JW%gi{Ze>ipsCf7s+3YE~ zx7;2uZoqp7mcr^Ki}I)p?PpPb0T@ApxaOi#`wQGV#Z~s2aQnfRlrWk&tOz?eG(7qP zy7^+z1xEBei~=Smg)<&R=hIWn88B2{+Cup_z_CuQ>qtzy==CFf``DATlFg>FOGgUX zSy{_HMwyM9_Y?wrJQ+DF6%lE<{h&@6lg=iTBT?uZ>vWL_x-Ovnocej;UHIYWL5ino zx^X>KlMjnqX{_#1#=m?Up;(p}r{MAy^wE0gRW`!`y;9Y3G68p*3UZHwsv!ZU57n@T0+KrXZd*jDl@F3KTRl>#~z? z!8T{Tdp!Hg^v)lEvTklyhlYn|b3_l&-y%i^80R=c>{{`^xs(~-ZfvFMvpyj6*coG~ zDXHwkGChu{%tX3pde@&61wV#KVEC}qFEZuzSi)m6ZXunfU-YN()x-SGtp_m*xv(;SBWsyl zFTPr)eHbuF-q_rmRc6u8+`LGCF)x>uVjn|xfogW2Z(4Pt6!mzi9S=-ubd?}eMLMa+ zt!+4e+OkOXOuQZ5(rufoI>#VqjZBlf`R)`FxYXPA`z(GJ+8-5_r_i3_^s6l8{*4uThLkhi@M*3K%&+RrTE{MZ1;|>H-Osu(? zT~kF)^sD9r_;YW*!x=s- z=FGhbeoQF9d*vbR^(%A+>Y}`yA-u1K@vf6;@V$FEuhAOYl)+Y z0M7&F_U)vp1Sy5Mm@fV~$(gY@J8Z=YdF;7vpP%NQ|I}@xPRU!ln6%$|TGt;JC+`)v zRf#b_zl*|_u&CkYrmFm+W+2F&SOvNX_`jKKl-Vd>r zxYUOk+|`=1LXHlv1Sio)2;`$uldl(d+>%%;=kqTZz z-r6v&fD&*szkcs{K7SIUfu3xTEG5Ex^M;XaH!xN z_lrO@)HNymG{Sv)tyFj(pUbQJ8m`k_Q1-su3^{cj@r5@W%Q5NQR0XBhX&L82=B(_BwY(X>wN&l3_Ctp=; z(lkaCJ3+Uvfecbu*s8*!&`h z0`Sbut`|8K_QN)CG%$pbXsGYf^mPRl2W+5})}9bPn;ApqM#nk4U?Hotl8Iv_Y!3ke zns;xeFAY90=UFmxGIVr9y8KhB#DUw_GPxr)qm)ij@5OV31w#j0VgZckVW4 zq_kL-u(Z)5?D3Qo{(R21vN81JgtqAIh!id4aAvmS4VK3dE%i(M=zgS%&6$3(P>oX(LT-KWGg99qM`Dz zX7$5nUUYpdW~w2@;Y6I=TFQ;3W>)>zKHR~nh^NVDRa#58aMzyWYNJ^Xqm`5m;`kqM zhOuLMKM8;iNA5J(Rq#~NvRRH}H-%8JfCks+r)nA-b(_ROaDsbYuydW!BDSL`3Fml2 zi&-|L{m|~y!}|LBuRHQ?uWdWhoaOU~c&a}+#uI#81S~rE~qeL z`l#v=Bv@v={||)qA1#zS1w1@GojKK=oQm0qxu|nL0>6#m>GentsTTW!aO4am*QI}b3C)#F`Q%xRp7^FV zCl$KRfled(Xk@IGD7A4Al@X7}= zVLM0Sb8w1O)M3mcT^e-nol=a)F9^iRY&8nIZP&!1$>CSW8lXc4u;Yo0@0BQ7g&8V| zP^;F)1xr3qd}bu#R90s5c&eKf2U}9A}2;}RNPziBHl_>Ty z%%_KKxTQ{5(1&GMpbJQGB6B4wz~Cp2s2DYVrHLlikI=Ut#icEj#eQ7(1-{7IO>ci`X$L+nwmM4*i46_hS2rigw?W1eF+z8C7n1pG-X_u@sqQRR5fx&qU>JaOZN`8NuwQ4Xe7?*i|b6f{c z@B08Z)nPL3h(hs6j3>qEde*xf&2fI+@Tfc-ya%WeP<+J52yR+_Y1xO<&lvusmC}vy z+>%dNzK4E8kLd?PRsiOZsUjQVO)8L5ty*F@7R7B_Ez{m&3KG$oOO(-)I`2G-mRnil zc2bVhtIx&s;XF%$p#K!4i?kcp;WZJLyN})PuV{&qNFQ3|Z>DGS0(Vc^;$U9QpE4^= z7W%($4iX$&bBw-sQL34E=zQy~xBL%{D*8L}<=1B^cl z4RwKvrJvu)UQyTUY$n|d<+tCRM3y0dlM{f#MVry4cAs@DEu6#4-C@o z10I4;{PiO1X5hxmrf_eD)zc_!r~fMBsv*dZoJF+b;vT$m7FQJdO7{JyWiQYG1d-TU zkm<&;D3I)>{A6|STpcG0=}!{0!PKa{oVKXH|S<7k^BJyVSAhI zlQUH@+MG(l`o}ezogB|5;-sNILyIABGidy@yes~CY2iL~!t71OQu8_ojiW@&q`-RR zYNK~qsF%M|&m*sL+7f!aj|q0C?hE|Qhax>(5>5)>FKPN z)fTt=?iVmISqfYBqwKL-We+^K#b!tRb{2Q7`mD7=UzhVyt7VRy;kz+mz$mj@WUY=s z6h1TQjPA>71WVexMH*&_F$v=rC)*k=v=2O+)3vC4XSu>dY_yjMArDj9N1Hs%dH zjO;lHxe$rOY*>IpwA*%lKT93!UFsi2Pvc)lem~#%mUFsQW%>bjnxCl`Jl}WrJ41h% zs=zmX=?B<(c|a{qHa#?`*_nvQJXJzz?e(YTN#AviRjmr99WsG-VBd}j3sI|Xo*iLf z@m7xz!WYM$W`_)HBEZZ-tVe~Gb1A_a6K$5l?9MgL*$GmnH)3>aV8PRHl(B7w0ERs9 zXK8W`1oK*_uzt+B4c-ilyXhq~1eP}Ljs<9hTtA?&Mo15|&QyMvTF;d9a=|j)K0FDL zn&T7m{X8j9DrxSMR%Ga9AOsXmYVrtn5^n3$Q4qN?Ad+%IZ5MmfGl7WjfDveTmYG#5 z6Vf9_vO{$Q5rIdo-PaQQUY_<&R_v{gYJfK_2M=$@H029XJ@FdwXz{8!NH-+ep zQ-7hDH6H?tD>Medu5Ol5j#$hUHC;yA^Llh1z?vcA6$3tygbk1l)Fv~u)IMHmZZ3S^ zsF2K`DWLcdBz|@0l4%Yk=qd}o?Xn*ecSwrFM0Ja^@TnRiwY878P6HG~3f0jqHbO(lk{mIj#KRNP#$;46Z=XcO=}7dmxR@+U zK#giTPP z;SKvwcTBsV{13A{!-AVi-hG}BtAMs}%28tZkP`HI^w%r3fpz+u#s?fz63eHqEf+5;1#hK8r@u?laQij8 zIorREoC8td59X?n5pT6vyv62)S~`xGBn#S{@1EK;#NVO`{7qi5&N2pU-;AL3*9a33 zor;rFwD^px#l>#ld3>PDRAak&#GD)gue_z+R<`g_{9ZEY*g!O%Y+b<>>eCia3LY7A z7&e9_xON@!z`xIOJE@9|&DXT{Mc&eOZ$jO%|IqPk98c*-W6qFFi`pljZ9$JYW~U`y ztF4BQZ*j>=be+c>@eih>pit^G`+HGyq39M1J~;%aJ~%IY#n|rg7uy{9{v2$B!w(M) z#e&gMP2h*T@Y1XcZl&Js_Ro~%Y@R!dKHe`w*bK-`1zD{1j~PH!tQF$e3zQbeUC$6% zngzvE{W?^S;$g5HqW(jl!8j$Hz~M$J%y|W?k2OoHD7XmX)wSUNQhLrh4vTWgQK2%| zr@>OTGE7{gU{tqM)EXPdHGt{wXnh&b2rJq zZZj(5LDOz$3u`a0ti0=76cxVFImytG3kaP#*Q`z#Mjjj-I0Pe5*;iLz{&Rc?dOKk?58V6SVAmW@DsTJ#S3d*&)AAf1UJ1z ztO}LU@N8lm^;a8LO;u4fu@@4OM3BSMa&I^E$tge6)D29J$9bg#XuBKj&-Z zhgWpZ-X|tn7j)d$(V@+}HV#aN{eGX6_WrtR8MjEGa;=OCMFZ=XuxpWS<7I#z)D-Ny z<1OkRkmP4`3BZGFX+iqf^nf36ligCwUI0+$g}zpOe`0PKF#@o=^N0RCii$x#_af8i zNv;c6h0N{56RO!Yxm~&bM1nf^(|G>4rb_nBtG9Kt?mCW@B!9XcvwZ3(`(&xejs^ON z)K2_&xn?KOVU#{ISofWm`7E2&O~PrQ2<3Qselt}D#x1|2aFB^BBj5(3z;7pEpF^KYaRoVUftvvamGGT z<}>Q`B2g2VZ~ky2F3^8#kteG(Zva~S*KoRjM~naq6m!+ffjq90n}S)q@B~T?ZN;BQ zr4#X2i9yK~bd=THHA0ycpC5fA^-p1~`BF34WXiyj{riCD1{2r88S~P-5TR<6vco1c#D*jv|1PtZn*jmm`_p%lR#4N321II0o#theF(!a7H*s3 z_`eeyP%CG@2b4H36*Z5KeF1=c(WIf3bSrV}YdLAIXChETeWfU}NRp&Pt{Hbdi<=*S z+0dSKS9gf_#_r!yqWm|sMp>8US6^QZl=^UEG+}LREsX`ZKZ8~_k{qd;I!lrg8pc=I z+j=R|?XQxK@B3h*0+`7!?v01gG#bn)M_NK|vxJeQY5d8m{r77D?3)P>Agn6S9+%0S zcMlNx)B?QhYUou4Y3zYvC|8w$>5+R80p}KU<-sj{u8>2Jh(VhS$3FtQj}Tn}wCA2b ze~thkfl|Yyif%4WmiI_(;rmPi1K%eZwkqq6W;&%Ie2(`b4ItbsVWz3p|KNV7Zf66u z_GRM$|CVFi20-Z*WNx12eP3U{>>;}p(qA)&oH8ebdWNAS^_HS|D#vY|jIFuncJ<=M zjQ9kMs)t)7rTv zzA^tC0Jh{{|H3<>$AC5XY`_`LZV05BR=^}(6@_yIC&`oS|Ge0LFYkYxgAp6(*;!y0 z0&%H)U1VBYs;;3ix&=%VL}#bc&wQ@BLdZ;=qY-+en+9+GfNSK00Hi8?7zzn@;C^OS z^Vc5pKd#SdkZ{$*!((fNad&t31{<3hAcA~wkBCf!*WM^{NRgzq;(pyU2_QD{SZTIX zwuewf`bOaYPD?^E0=`tq1l$AxmzP7d3BWcZz^`8SI;=we77yubUKj0{u{&8zMhRlwGfIwIXMY-02s_3E*5mSp)AUk-vFgDyZ7y3Zw=Lz)Dq)g!AQoG3KX_& z`9Xr3aW3P))X_gVt$0u~{QCO(|1toN3iLA5lqAA|&93|5;g|r~01FGIVH8~ zfAUW*nVnCzw7d*x*TwqEvkw-DI_TabY5LZh|I5wAS1XiW`v%^_B)stN_M+NT90eEu zVK%L=HoErOsk3$IiEGhNk@Yvw9z!mB# zqjD$e2S^LX4RNP`LJfjDr z26m4m^-W1hBfyWS-HRNOC(IF(k#+{KGlsFw-c^;nG`IEmXrIp`zd1rVBbBd@{q>mq z|M0e{fD_sAZvyCzd6^lnj{+jcXN`^W0bc(8{#_W zvjwhPCsbC~hJpWWBm7bRow}>H_ane$Q)JPiXlSLr0X=q`)ZCk|h_g;Tv4|>_YwtSF zp5&;K-s}tdM`4L_wiEuz$w_>AIzM}yCeV=r%<;X;SUeM!oNQ~VqpvS)+Qa(hKMmiX zV$Q8AKxa!07^mU}h#&%f6S-;s@2&@UC6UpbflS<`iedQG<84!Q^#6F& zfB*QM2bi^H0v5)ppo5b;j4b>zJmgHlo8$~BDlf?=dry~}k9<)|^~W~{P2&*(&s4^5 zX#oUeBgNS6QQ*O@k_Mh{n{@T}mt~LH(?h@TQPa`!XtEB~Ie=r$|K{oN@UP%o>2Rt) ziq~9NT-4|tFn0Vd0?Ob>wx#0=*+`fYI}A z1lyFr0_4jtBGRzJ`({(6-9R$@cp0vS{P%VEPy4U@UGRNsB9A#hGNQ=U3KRjZlgxL# zsCUAju5nKA+eg0FaBboL8e}Z^)u>E@$~Yd-fx13)wsSG1ukZ0_l6kf85t+QW)2GIR zJ*R+~!p`unqJoSySF4qt%2!?SRJykw7X$bsWJ{AcSUm87WBU!NB zsw=o}#?Ry8_dGB|>R9%1+8>NTf88JhZu?MlF`FscV!;OY+I$(FN%AZLfCRE#(G83Zaefly}+ zX`c4RV0$xrpY%>`wQjYmPZl}zL_e|^+o+{Q+}+C{hQoTjXbX?2u-TS{Zx7f++<*SO zNfnD(($*kSb($#Gv(f2E;z0{0B`V=K0iD73RwmU+c_!@qovhPSLg+5XGSq68_>1Cb z{{yZ7CZ9u&TV^hGMco!dILsVZ%f->x?N!mvEKV~xlDVe8KQ>rf(WH4~Y+cE%P+Uu! z(zHcfjx>xnhTi*c_Nk@*wTWozIoh{zakaCN+7BLpuG}~Q^C&1l^p9dZpMs!o`}IET z(qsvbZ0744-YV*X0<~|8SIgZN*S6um&niD(%=$boQbDP*6%+A8PUrZekbV|7bhMK- z$Sf$P7Pb1ZuV#i5oHFkWb9~5)mH%PU&-UJ6OgYkEJAy3CH@J(~Bfvz(@~0Ufbhg@a zjkx`ljef$Nq0Y&m6&v07P)hAXjGw;nLoQk^Psl<}+1UZ(fqy9DbEg5~*J-`xcey<{5|KtV3HO7?g(~z#t@~NclI(JXD(&NQp(QG_)?m zuo_B3tH-&J7}-Rd5Jr*m-@1-XRieYqJKZ@EY(f^n)v7g4lUv9Frkg{Zdhrm9;~KI<75d$9J+Av$G;gch zvzcM3Zc+cP`u=RKMNeKE@w79ufyWM41pSo7s8NUlL!6R~N}r++MjQl%0K`rPVcvfe zfD}68%Mzs~CJJ`3$E7lJ4+3sQgHzo(faIoo6VRkif9_$-aB)E9gV_|!6k4aQSf>Lh z+kj*^qUGGt)8SC2uJ>H` zDD8UXW(ElKoLtw`*3n^`tlzgt-QRdHbWu8u^KLj=gfe(8Au*x@*Xt9 z{2cgCw#Q@MG|c92*I$lbys4>w3Pj(I<Z_kzGExS_1BR6lv_h{2JP(Ar+jExY zj`go&+iOHCvd?{+$ywc=enaSX{rYgHQ{HOxu<>*H^WfPhDsjdwL7}}_ApK_SIk9oA zOVbt{-Mnykt4n4zg9kw=!@DLbTipY)c^6v(=*)Ch$!qH=ZPT6{R0=PJQYH6PSaUq^ z@Su@tKKwRxT4w}=7`e_?`zwMKXLYeI6s+H&M@5+_{_FE8c#xzY*H}QxegIl+EgtI-dU(tdqilOBW;1^6J zohCQ~(3Q2U9tMV0K zD{?o?lT6I4tJ&^)uPQwMuX~< zNhq>X7ka)SsuVWKWhyj0;b%XhpZ1F1Rhr%pKI^iDAHjr(S<73@6c?)ums6}_Snn*UTv`8*%IT=F@;jzV?Kv!wE7yB~(RM6iH@9cnv46Uk^Rv(|N zccQoLO<-;n(XfwfUK>%x(OP0>tym`o1pT+2%w?N~gj48j0$|Z~lNxKEjTN73FmF}Y zvd&f{vIg$ttT4s!J;JOeDs{i>SE`;iW%CIUpSr*^ZrWflK5D(O&sv%gO6hXDGj01V zMF=uL!Jq}HXnvj(h(#ptt#SnadJ!R&%pK=qos~S>pX#}QNSEq@ySCUrHKdaLY14Ro zlwP(p+a9HknH|`s$M*axDuZo~mnG;co*D!lpPNpWz2KHP+o2z7Y=4NlTLDHmnA&z6 zIQiK=#m>4km{GdUsRC8P50!n2$T1%a^mR>kL9H%x<63ac`UNpKxZ=*|`_m2F{ek@m zn3SgQn5;tpv&`DZAx7y=T1@>Cu6?NFfvu@-KW4IkW3qW8yf!J&Ca7bJp^6kJo>i1z z|C^A*A@y~CG9P={xZWjez99VML&MAiIiC-S{K4N4h;(f3mKD)%6hE`?Kxx~uB)|Hj zA*k5?o8FrdIWcxlFdDGW*|?|ss!;3{R((x!=B=H1IiuInZH?AE}W*s zHL`-i(N2@6wO%bn$;Bqs9WDLF1G0-*{yNN(0`hCeGyAEMj4GRmlq@bPMe!emk7&tx z@5-U&Mxz4FJ)hWWZF*M*V*w47<&VRC`(?zY zzxH$wh~E(&jk1aV2C#Qoa>hfbx;urTSyqKiVM?o8pr{O?$5<40V2<$7rSA?dCd%+? z;X{;ef@jMH{&`u?J$OyAjLDu;4wk54{QNn~{s5vo;XP5P+BspU?ycn6w#pc%s!H|Ja?oY$Z)e^h$wE}wRuDyo-K&t>NkQd}1~`_|7894I zlMdDC8uSF06d11Ce73=IaTFFtD0A{@>~bp89b%*xwZWH_x*35R>*r>u?|6uCYJoLnen-ysO;@4B zrlUEwrGs%;aQBns>V4Zvw+-jXib>?Ty=_%ur=}A3;li~L{TZM$mk%#xUm{d(JRKr? zlaEh22G-tC5%XSgl;pqXGWN>P&Mo-DZioHT5}iISm8VKR8TtnsMk zlcd7LY?!>_0+*l5!ZY|b>I&5_iE;1B9&1tF5x2<1U>(WyF-nf11dv*Rhjy~{~Hm5_7*#V43#UG9=uClvjci!*0n8X$(!tU&2S6X z!6M>rQ!nPI(%Z`4`K+=6NA#@ci#Iv_V9l6Q5X0JIR@pai3}*;-8gz;4?9$@j~qU26<)t&PwyTe<~Ip~#8I%!9Q6{cEUEb-TiG8H<;QIW{$I zp&DE3H0e;#=j*nHf^J85Eoy{{X6%imkc!FV{f==(yb}#vJPn^>I zvr<8UZ}P`UMw_vUKrr@W-Ph(w-0vnN!wi8)yG6|Qabs&Qn3D1MeWRjlj#+Tf&@-7I zgx`Qs80MTw?kaf@ij+lteq=CUe~ z58w}kBvfw7I(Lp+l)MjuxBy5PoC#GjDKLir_Ra;&444r6taNv=GrD54|HSH~-VrHcI$^>l#9*?!KS@SIg&TyFDi%6PLrLr@_i* z7RV=S#+AseTK;HF&133)IayM7zQJJ}dDFSf6EEQt6 z?^oKuk)>nKl{PIxp&Y)?7&M4my~~^QGG)QDCt~NRtFIP5k;9o8e*%_o{90LW?}v^U zDmTi*;8@71ak_%46d@5oAa)ib=7YjdNVI$_FBVv?WY88|ZhW5uS9M&GKc!2yl4?l~ zLPWsT#elA+jEzqEf{#~Uo@+1CeHHKGfDJO_lK8cBYiUd9BU>Ar-F!0@be!G6fxKWa z9)MCw5+gRUdE8E^X94kJNtxBN2hJVjO_EKTr)qtCfQ*pT6?Ue*h%P5LNb=VZqDRu+ zv#<~3VQZ6lQH_TyfzyHa`g(>cM%__{srGU~2^5>-bWW@`(2gO)Ym zjvKw>%R4KA84gE=1+cn{Ik~MpHXJH}rGbw808T(askCsvD^<}nS9d4Oup^qCPhaV< z&a7#vg5UbrK<8G4T((NVcVDj&>0rD#qlu$_rJ-+TEa}!N1R(KYwda9>ACyUeaj{lv zRIUm=zfs_ASYV@0O?to@p@p<}1qhb#LXBu*bnZ6w{elTMZDRs1qw|BjDmnOX+hkcC z$T!YNwQ1Zz!m`Jc0`L)SK^8cFjrOKVw}T~>&`Ok^)ZWSuznY{h{r<1kXA^gpitgN- zST?s|PDe>$Dti9OZsN^eOgEmKwCR98PJf{QG!Sx!hK72N0yjToWtp>>)vY`td1bAi z{BZp$-=f53hz%{T{$T4mnVk8Hbm{!%4`OqT?Hn6|xIz7xWO9qrl1<7VZdBhl@s5j= z$u{b+hoj@jUlL~5=IT&^#+vnCT?enUpODdOU0k_pXkeE_XuCn`+{p$EgfE9+<>kO< z{A|KaCSzqt%Sy@KVCQ^!5D_ znjbo|)+spTs>sqSMPapw8J4ORhUdQDn=?JE#Y#nzhC%_r>zQ}s-+Rp>QWv@ z@Uz?UW;+>;JKgv)2jy*KSE=ekuVq;MfS_hh%8Jboqja*w=Lm&#Yo3(Vo%%D0*ri;Q zR}iV%5txxGHQe5#iK9rc?NqW(=I{$Fem>CrJK$3>QB97BMG)3I zFC%E^VNE#EhsNq9&}Em_>|#(S&V9cADwBx#YjrHs@%{(pNRhfN)&Ei9`?rr!6Ylr( zJ>tSY0}!-3hX@G(Q}fUf6&NPuby=`mD-Wstsj0MEp5e8yyX;_G;5X0;0TTI-vPj1>m{QuDVVkgb}|!-qxigFJ7=fmhV0_uCysBHmx;pK0h^;^9}{Q z=}cJXUiwLM&6fOf=1wlM70ERoLgaOsF1Q$<2DN^qZCI#rs|Cym-G}R{{o8#hqCqpf z_TIgN4U_bk5hhfS47TT#sSA*&#U6^K-p!vbtt)VFJ2e7=Pzx!S_aMDF$ZX%Y9L3qz z8^8(^hbss%_}nE?^@ts{zZCBgiiMm7d>Nk0KkqUMPlpbty+c_+XCGIqHyvJVTO!gaO(6BfklvYti1HW!|8jL zJ1UlKfTGQZD53f(7nGM4aXk>=z*$}J=IrwTM24()d#baZC#A6XF^9Bsc*{`f)l74> zg2{osnM$iq?bjpFQ`~#~O4F|fP0_z*##eeOmj4fBUmX_Zw!UqEj36+Gh$0;#EiK(3 zEz+%Ycc%!_N_QjO-64W>NjFN0l;qHSYusm_ea`vqt@HgiTo>=mTI+q*llT2RDH9tv zE|RXI;SfN+CTo#@8F4t+y71Qj`T%(n?QSEZ?DT-9Ja4uyw2@}Z+?J?K13^tv1L57-JKSRbOjmTx*bllS!Xmx<9P z^CrZXGx~lbTdQUua>RRSbR2h@daLE~h1Wd*r<;*?@!^Uow;Ykj&fMg{jeG)K$h==` zGtc9m*ox+E5{=Ynl|~T`N3S3IB~I1Vnpb}cqoX)|Gg;1>l2{>?i-^bI!qAuqK&^i6`Nj`1Up z^OOsYB-i!ff!#8U&77ekf%S^eb;b$>2V&u9 z%XAj5C1TgD7utfF!=e%AU&p4m@1S=>lrCIVm?uwQ^JO;rE&NU*D1x-kj$UzUq|_?P z8*J#$KJ(+y6%QnloNkqeXwF3d&--fMMw&0c8ZAii?4C5dNe9iKKt3zRuI7hZJ$?WK zFrq4FV}iAr>H=ffNuZ@r?>GhL!-sn8*|L3+B(Pb1*!j|o^rYmy~$UohU2Bp}jI%CSApuqV!ZAZCT`9n-L4M&|&HXSfW()Repka2g(LBsfGg@Mga-2^*hNA!W{5 z?L1;cZo%}De-%0U!GXIiCdK1SU@FB{!oN|3-Sk=KLS~9&5@+c}5|ZE%mCC=1jsLgI z;iX0!8um3Jazr5kORysZ)I~mF3aQe&cf9k=+^i)qe|Vk1U+c*>MZitw(Dg(iqAEWz zZjuBx^Jw?O$?407&8}BmKQy{$>iRkKlZfytyB$~B)m|9XpHG?6$7og0>c!A-L3K7F z$TC5)SL9^X%*m7Y1ctb{`}l=<#>B98N;WuH~FD# zMo9U&1kpiBqTA4pjbXDF+pw>N#*=M*<3ZxjTOn=m`(!rXq$$Id_J*&u#a`3$Zc;Rf z%5ewMCykj4smlt;me=t++(eRj_tQ#zx6ZWPg#vbRYHBY=t~i>IPt~uz3l;JyfQApLjgo6|`EW5>Ej(|GjBVaxzhz8TIU>H+!oRQ-zwF zCLjx#)Gn00XBD$h1bd5IELp5xRPDE4@93|mFI6^o%4$ZAhReV_;6~tStIzs_9jf>8 zPoIXz#O2T#SylR4zKokoh1>ZkYQ6J}a7v=fRNMvi@82_Z>TrsozF|E zBsenUm&P5lN%(C%_oiLo>xJ$FOZw<~2lOMYKVoIBO%gDfA{UI)X#1^YGy_)yF*Sv z@JK${RSm>;0$~qlCdsKep`;r8Vp>{FiB`L+Ri3At^&t&xhQ7_kuAEREP#v;qd6Q)B zIaSRidy+9rYM3Pd<5sfcmg?@8(5n|sqB3nJm7ES(W73lWe1MnXy;aq*bpr3nL5R z6+MZg;yauzei^_dsK?DGAbRV8UP4{|C2@px7V!sh_NC1ksz%H0hnBsbeOs8feD1-P zbeYD^iYb1m%qqrt(?46CT?WeGBI}z~RVSE^Wz^ z_#+J$SChJx$bCpVgdf6(jP}oAJMpuiKX9A6%z^-197N=^t5IigbI|OnOkDhV zB8z$aLc!hRv(*&yAu#s&cx8HflXpIH$7Uj}Z(|o!*n6j!4X%I-%Qf1vpBtfnNvw*> zg8imyXIXiEVlita);8;IVtLth5{xG=Je`j}(R%tK!H_*qCULV;swbsE0NcK_8*FfRh3z{ z4QV)?yWBYRa6AmhA`_biqYOka=$Cz;q6lsPKXbX$Lc0Y4TuhX8{sxRr)6XybE1J$T#h;fIFrAN5anHG~(t%_a*}KS@`?luMf#G^S zDm$MHhiVr&4pkb*u6p}+VHv0ekLG)X;oI^Wen%~Y-h-5Wd+Tg7Ej@l5vN?6G#PQ<; zIf(UMQ`rU9Yw=i3T)$2}4NEj{J!YCka=|~GU+K@gET_G3;eGus@3B){qhH-I-&@Q` z=OA84+@vmu{D(l~eQ|eA{Ve-K0S%-N>x{yf2WElnpONA4a zh&;WzS%;519o+OC+l@wHT>hQcJ(rK3750_J<)|W_Ay&!CZl-u zwX#!%HltBV8)Z$-9^J;s-k0B5zL&n-658C&FJI{nML`={TK9e7eNv~rZrrsi9ckc) zuNO0`J>#Cl$RotvC4MmrDC4t7CC=EF1Fj5n{5ulLnXZ0GEtug zuc}ev7{UO#(P4mZ+l-@r^S;A(&?ucZRMl1sh9dB7A2*)rJphEr;4WcAm|Sjt+Mcwx zH?eKceHi-n#RI33eQ$jx`za|;O-;yM$XARjgSHwTlN5)sk_?-~_PV;8Hb5KA-oFP) zn=Yz9l#sLCZVVf7OW)N;sq7fQj1v^<`UO8Y?eVc z;@U>@Db1(OwA1)83@<@_jV!ye_Je9=iVH#Y!G@Mmg6nda*s%Ty8pEXYNr4HmxVVG} zNSQgaUg2lvJ9;Qf8%ZDtTYKT*7sL>;ZrSk3Ky%Q%rMnC>`sv9cW{^i+kWA+1&6Vlp z1Dd+v0yyP)oL2A^)tua^h{Py1xk8~W-mfKFD}#x@7Yy1FqIP%OE~7V)Z%Iwp>rlG zLnG}r4`wsx8->m~);{KGE5)aVPov#$I&8naxI%U4a&Yv4iu$#5Y1%>JbG7TMPhi=} zdl^c8$LQLi5Q6Wbazy)R%XR!`;n_^!E}A288%=Q|U9L2yLrR`T4_!QgO3@<6y4({cQ5OPMi01&1S(YQtInXS;<1)B);57{&6N>`*av~GO*Qqyg?Qz)$2tR zyZIC?`(e#&3J0kQK_Bn z9JUC{mwqNyvO8E3c5&tYY)TSG>C@1+r!~_qvlNmSu(a8XfuYyqh7w7f_A`pF>6I0T zeNOeJFOJ2=3e{;YFY1MEKiHr^f565PX7UNvXS@iT_l!7LaiT+)zI(He9KdupH{Kns zVqiB^SZta^Xf9$tC>gA=#tsMyVSqVTX!en&$+<{la%L!ur?%Vy#aHHmb&s)F5I|W`oQ{J*l^H7*ZH?P6;R8n0#gO7*8fK z@No&uEZk=p*`_~G;A-Eq>AseI;rq6^+b1Am`BPjmXTn)ZeB75T!ttJ$er$V|ws$|G zf8es88Rm)91L*SCsjGGpU%p%p@D+!X7*L~7+P;=AcCWY16oaiVe`vq7X2Ur-(;qdd z^&Bh_jAN;IeM5G?`4l67N&dAF|Ep-gOss>qQjSc+eLeycNpel8$agU6g*vD|a?ekZ$4T~pSMmn~K1unLN_?_AR~WYCWs zxG4|?3c%~i8=6gJ_{DibB>>vuh>4kkfAJoSGA&_Az!4#zdlrr3xC znyxNFW{i83oF)>0Yi8?N8;*JhC~G;d?DuOrNc(=1Z)YuGhGS0V{kIYn-^aFgR{&{c zDz$!w4kd=B-@=wbAX9ew#3fB;6$KYmVUBbG zz*GP@C^3dhgzp#lG~(9Ph>?*j0Ar>6{FxC+@W)f)XScy2OQb85+CSvw5^0xpY8n*x z#Uvm%AK+{pta@4uhk<^6#DsdSQkkWJbgM&qxxd*j9ssP=J>GSe7jcY&~l_C-1WoSN^cUSW#f7BNZ|w1p(*@FoAgh_ z!Xx4pp7c7>uy+HruELS?ldIPh#fh7=3h+0~6{6~dwf|Wfz+r}7yAKB_a)-Yt>*;74 zAt4ifO633tFN(fc+*a4yY;P{%PgS}Ju(dI8P;p_M0sY-Sh3Rh+9(l#D02wBp+WH}x zupQ6?&{3GukS!84hxTfjph7guYA)(EJ?|V;M=#!gu@(Lf9K~;prbgb)h{_L(J+u`}$fkV$vH;Jb~-fIRTEJ#dE zEwS)@EUfWC8#93@IluAsUz`B7B7etbS-EXn!a`J?{knw09RSe#j{fCWdj2mEDOA;~ zmzJ5;w}WQq=1qWz3(RFC?U6M7g--kH*=MSN-S=@7+`Ms`fPjN8h@9$=#9tx6{}K#p z(GP%rk@eKgt${}XjzGQ{+F4Blpz1ibN@^nik-7iX#`%f4xWwYgDZoIHi3v_%tFE@Q zAO`J^A`Xp-p;T3!4Byy^1(6W|UdVyl`I;;HZ$#{`RsZ?P3-va@n|CGa0raqdj*bo> z+7cVaBeZNU3Fwbwrca9pARq&eAz8`%!&J`yc>_3<04H*LpeUCy{e2wX`-KeS`@cAv zKNorxiCTl0nMNH@N-0Q4w0=JNv4!L6FNF24TcVK2?>j&VN7dtIdqIK9dt$8i3z+C% z%ke_R=^Pk{DcCRrW67c>CR9#6;jefy*-|zURNm4EQmuaxef-B8AP)bjEL<9&H+#4b zn>7JVDy}*8i#pGLtU=#e#WIl0N-oa3;&)!N{nA0&QK=| z=`ipCmaOc6g9x#0O2Iu7w>Us|Dl@=>8?$KC^;`#FY{ zAVLS_@Bfp_^V9FADAM8yD10DEEG(>N{3~L>U-EqD|A$aY0|2X2z`J)3p*kTm$TER{ z9mp>}E#C##wy9SNh-Fw!jZ?teLV$m*RWwFS-yHe_g7(tViiAyB2a;f$c;uSMzr>m= zGC8?PjI&+*7pDC`e#5H_qIU#zz|K>^;)D1+LL=_@>(>3^6aOf*)5nAt~ z{8s}~Z$Wnhb5Z{@H&84r2*v-0mb?F>XkE2lbVuHTOGw)dbTdOZWMEgi6mFVaoBa0w zd87Zeg-2em+PU-$SN+*P(b%t#MdduoYJYU~f#P3s{EJVid8m2@ak-4#S^=_8AA3RN zfMrv(ymOA2Hu>>CHW@29sPTWc`1gN48$~t~g;)jx;g~KGg|o-51i00Q1BE?$Dtq~h z_5SCXH1j(+yaRNMGB0RpseLS7D?{r)w!8SRiwb-sK)>wj?vB5zIG1~6&iUAPmW4_`02x#0)7_!7da99MXzg3 zy|gjn15v>K$#n1TkB*E~08GZpOR+!bfrqz&kDK3>IVg?Lwc_U|Z;heSDpvkJ zUTpbf_YFTJ85N-ibE>Yzsj7x2ZcO4pNPuyi<`VBfNLli`#i`bVX4Ll?J0UGXi0Qde zC1SExN~+vkz?0U}A_OtPq0A6ME{91ie^b|$u&5+D!Vu-3TvyIID`H_77|OXUtnq(% zz<(>23bz) zi$bIlQqlj9`hb&tqmsFnx@TG9iBZ~ur#!#n`sss{6)`-N@&OH=SuAu+kd0beWwWM)7T;p5x9 zzkSdD`(@8QA(@H#Cu$fEWdx9q6f?-l$pN2P2j;)^zyJAPdh5^c{`s@K;?m~SJ3H2( zSp@J*s5WvC^J^5Ph?$uspFe+|p{0R;pCoUhF^%ib@BM3IfAi^?gx4+YEYL+k{HcFT zY%Hgq&!bGDQG_mLD(X!@r31l%A#fbU!~me`%@(>QVvOwPs7Jjc_kMO0=^VfX>5Vn9 zU-7X1lKULNYw}roPbDM*$=QrvxZ*@bM@L%*YKnt4B!ZfmGzjha6~EEdw~m0(hGiM3 z{C%vDMh+NQEVUpWgr0u3jLcLH7Ef5*MoAva@BgT~qgD9NUI0MMb{&H;5a{6n7`)Hm z?U(lS13T8EfCmn)R$iMZVpogp8XFjMA_Dlk<|*%iefGB=l>ikHK5{$^K^k^&FeO}W@^zzP^ByX zr;R?D6LWd@H{$$%FP10><|vXiK_dh)K*z^KMr@b5aCkiEFB0wJ17Zvi;+VM6tRZG; z^^V-a<3T#g8V@2M3Q2|__C~XQwpajWhl(l}w7)XF41se~fy$-G%+6LGmV7_`Kj--O ze?EJF3|CzTE}0(ZCo8*qZ}|PEj_z3X{r!Lc_i2ql!KP`&Wezt`eV`z%+v&c{gox9Z z6Lk$cC20fGXAo|peuc|ujfwZKJ>BiEUA$GEAn}YiVOs-tk_y(_?`H6kZ?A{rSBJvi ziam%5#pK~uWnwOeC+-?<-b5n7o74S(^Y_gY|63TLd_YYtC5+w6H8u|aa&X(nKSjMK z3K26fSb|hRDl8!2wY0SK6wKL*jEsc(7^#F@QAWfI=6Aa(Op0~$hW7&Ol)`K5-j2O( zEgm8gh!_4!$>$L@bvQpUF>i`2i1TtFpF;_+{4$UHr*wEZVV9`uKEooN+oByus9(%= z?7=|j6doBD*K`HE)m;Xu@O9T4H5!O4bwQNh8#mAOLj_3us18Hdr2o?i-^!k5_^FK*^Y8tAM zh<{=t{?6%ncxWiUX|V4JvDNIaWbaQ=YV+nNzs)G%4|-GWxHKY>EPTzfK}Y047KN*Y z5G)9il<6&ML6(v1SL=vm?TBTNHUgo%DItMSYa7|xTZp_1ynNM9GWPmU)nlo^rLUb!mCkH&Wg2S?n&p$dEf zfWM`YBFWxBNWYJ0dwu*U2!v-F7Bs$20g>~xq%cIpp76Kc1%d!Z$v=do6*58uSvFR^ z@)6l->Kq!ln8SENG=hV8@8{-a=>Icl{->k%@}+yGpgfpw(SPyU|3*b>)yh zMdTMU&wq~dh>k7_?DHnlwe&*99I(r6#CCb*S~SoGgMg~v{`Be7RB)__nN4u4uU}sS z+6Rf``!?NDFG8Nkhr9m5q**pkQt_0HY9oP~@HS`3AZ-&f6-3K04+ ze)#nVZNrY-cu62F%!s)j2TG|01yX^5fl^RXDk|~Y*x0!cIe`D8L_}h)TmyT1d@pi; z-|q7ZA4+!i@e^8R7H~(P2qkx~Tssg=Eh%|cR#pZP97*764?xVfjJg)~R2aN+3d{$8 zYUzK{P(KARmG`Dk>r0T62&<@IQPUmCe$Y{i*e_M^tE$Gq?;$Z1nleBM$6bSldX-}_ zabaMWpIzHphRXDNGK{9M%f5_`>wQia0VpqOIHxaDF<)pY^*Uy#!{)n~wl<$9HP3%h zee&WxHhz32Ayry=PmYVtjSSMN87+?;M3L%WU?Q**l86Bn~wLSE7 zJkFZ59GH6ZMnig1?SyF{D|w zsb035GN>;zl_lxBu7K7Yq3m;R@*Wq?0aWk9;^L^p2tTW-RT#a*wB|ji8Q|g5X0wSN6VJ!hw?^A z${aS;oIw-)WdJb=zstoQ~O05q#LLC;xM7%ctw487&P^azA&=y^wdjnKMVs? zBw*u;u?+O|(SR-`-*ovE<#@fAwG3>g^Xlm~CFo8Nf>&?#^>nv~p}AAU+waMGz5OOB zWwKR+6ZY+;{b3pFv1#T6-5Q%^31`6L>MJ5FR_=dtuAtiFR@-paoxj`1KHr_2T@iB~ zllud&-5Xi-8d}Y|k%Dmt0vFlKBi-6F*rsFeMg3+xS)n?S+Sj@nl&Ko)_x1zx;oF6$ zho?lI0EgPA7sBHZGv-G?t+k#w6LIPm5gxG=88O{+a1lLcxq!)c3L90XWy7Dhw@8^=N}^AFLbq@Rdhzl$7%6xbq3(_ z_ZRjw+WBj^k3Ke>WXD9g}hO>tU!@C~8<>fJ2oqH)f<<&M-6WW~na~R$rK6GNw!_slM|gYSPBAX&fYCJ|yg_hk2Br zC-xI$w#FHDBA?$7-poeBMc-f;*L0Q6Z1F91d>gUj3{#vCQx3lGUcdi+^8Jwcz<{TK zua--#?pMN*rt<)s`Nl=5RH1RljTzRwcwg6o{>zf1^_-FqD|qxy2drz8`60Fwl!h`9 zGD-CuJ@2<`6#Kb~v&-?hhQDsu7X0W$F*wlF-HsFqy4!V*$&Jq?wbfTIHp1Z$f4pQ? z>pW5@_Y%*w*P?!t+NGBa!_vI?HtaYnJG)E1+^}2K(6Q*n@xDBB;gt@rq2fz^=bcY6 zN$2*Wt#lET(m5>t^5d>}2gtO)u(JO$#MX~eKcNEC0(_C<#eERi9_2%eeiozT zsNOEW1Wext><-bohWl^!Z|B!}$$0TcgQ2eKhMkQto=5LHW|nD{*@lZPiLiZ3sz2Qz zsmSv_e?CX3>$z1XiRNtH0x*JC9HD~R!I$&O+LJ;wZtt4**f@&EYvtCr>n}-aZTBZ~ z>`T!cXFP%u=UwHW30IqD2GVQ355cKVNgmiYMjonIlS#nw$q7p1Qb}D+laY*$oF~(q zOC%Pyzi=tQT^*>*)88m8H;89*_toItFmWyI9>CR(r99nejF}{KZNiH_I-K67-pC*S zd>E@M-2A>wycI{b_YnZyESeRq^Vnm2xb<7#3)*oF&nK4Gy-rVGKcK385LO7BMh#Q< zxY~_|h6WeU<8zc-(Y1TY%;RaB*eg7z3Q0w40deI^Lo?D*xZeW5G7i}BmQWSDA zXGi1L6I1;`k>#idI^Iyur};?xyu~r277Gk<@k9=X!*TW7c%WOoBkTH%0L1lK0-IP| z%<2F)moo41lINib_S2(p-i}Gjs^zPl6hbyh`aA}X>nZj@nZ(cU9PBm{bAP(&=5}x} zZsS%Tk#xSVA*R8u5x-IMzSnt0)fseWNHS-Chfi`HMdJ~X$9`#nTCIf3{>G-+gU6{U zi4#Q)=T8A#v-hM9ul)wv2E*Fa0e%<84JlUN_aVI9TAE*nHL*U#MmpKhp))C?Rq>Yw`_C^6-B9`o`{g92T0}xs!23zcqOL*Rcl2?s@U^ zGchqOFhi`{;|ThKTpCjhlb!3hcb_@u2lO>IYt|juO{sp<-fi9;a>F(nTr``hk?ZHq zFUOV|WW%*=+6g=koFMjT+8_Jy`k}1d$=M#mQbvR<``$_GxgZZ4#ClJf{plszsRbUF z(^G}VUx#JqVh9{2TFe|%wy7wqW5h#v7B;e(YhyG?n3J7`3b-~$C-OwjeFaNTxI-Mj6%5zCdaT06Vh8Y>IqFn{;btmI1@_H@^E z*jsi?^ATKyQs@Jp!Nu-Q^zrLwQ;CLYBKd>7Rm@ zv%<#3RBttW({WyzbY6La7aYfYdXt&RwP}iJ`EXh^&K$33!Zby?@VVV`LUFTBl>W{5 z%{L;$%Yih-jC&_!p5Mti(q?xICO4}&U?Us7nE&M2|J$2My$Uh<>SsKhCH_aJ{dPmB zpwJCGw!yCR@rwjoPj(C1unkR^odf7_VLenkJlS8?-vC-q4V};ICE7bYB4L9trh4+# zuC=cxS#u5_)?g=%-P|e>HG?jA!{(z``r>-5yDXMl%M9fn*-gvay9$ z8P~_3C%ca^82v6cyW=~2s}C3b93w1?7=lKUAu-z2#ZaAX$8&V{uBDFbc#-NijXa08 zp8|1qN0sM0Q-l1T&~a9X_-lrd9l9CvaR^~>6-3#_k_a(GP#Q)lKRh02LFrDrENm}-(|uQs`w0WmrW9v&LxFj3b36qk-orQQFI!~n zeXL=@VHTS83gycCS>Inn)phPYpgmeB4>8e17aSNQ@VUorl&Zm}<1`X55X&fU!_YjW z3LD0p=iKAm`-H3AEw6+V{ARn6l1SB@U#a+l#-yHJ0oP|RG~fp9Mi*#kb6SA0`{nv) zIwPj*^^-!MFa$>ql1qH zC6R=Vjx(}%x5fTcrKxm1Qa-OQxmpwk3kj3wMUag^^VR+z6WzD!NU9cE;MUgG)h-|E z16h`hcIY5l#g{a!zHO@^@oZ%DVrj_li5P6&37uwaT8Ah1x=`q%0m-u^JQb}uu?}Rx!BGx&X~QK{UoLtL={WG znOgoaR;UkDR78xnDlw>kXM1u%N-1C?iNt)rb@sh(kiJm%`El&FqlzUseeWBZi|bI# zZM* zYQ&?s@z9t1tn*!EVnB6Oj}k1%Z7g2=o` zAU}ZC4OW=L-!)O+-gVTlYl3m<03{u>wB5?J#g6@bJqhpCzjIJA4;*nw_S3iS$51-X zM`V{948=?>cFaKb~iD8I2d*&5PXj{!A%<_2WP`x-Hx@$1^@>L6yh2mDCiWV>))ERdwmaT>%IWmHBeo<|DhIJ*wa(t~9@)q38GAx-xh7 zhX>*}w?4GCbv*0=ZKrg`)-fHC-!3fZaI7s2F9ZLcd0LjEwo%Gu1Iw_WK3+J+mNU*h z>Ft=5COS9dG*E4aMgJAIP)3nvbT}@(#_vs*W2P&&yiB!$O-hSOE3g5Pc$JqRM?aphWlJ{jzb5B%}@ZAUf+ z%{qntZ-Z3dMViZZw&Oh9Pdnd|6<5E;S;k?uvo|xva!uK8I{wK0qD}+1)f~s?Xfb4Y zXsazEDG&4TU?N40;v+_|*;_EW+!DBE?)?aKrr)7|rlMk`ru)s+s(AcCN+IJ$g39yf zq_(TPlwgckSoOT~xRyC@C6h4d7p?z|!kdD*Tz`ZO_F9Sio+}LW!m8h{RqpXZAta8` zW>cup^l_b`&9mLQZ;eI&R zqdIoq-P!|IvxC#GtUZHS3#e9Gv+{1d+9SMmB}SihYHfQpnGE}x<)-&JU6ZFZ`?qIl zOd1=ZWop5}jjkFBPG2%{Qz9B+Q^SNhd7@_TzK-1z{AT-Oc{Sz9>dC?Qe5?{lv5F$g zhWKM`9haBIV0K*DSkefHV7 z>v#Of`@eOth-HxfD5%^NG%^jY!4$07UIZxVr5Nq#?mWf(4B&bxt@|0sjiS%!(j;hu z`2Xx=+VXi>Y1>AA%j-?&lf41Hz5^HRhO)(XT-`F#@v#rIhB-__7gtkaI(^X}6cAER z%0-doO(_!<03Kr(2%a;Y_g2EAqt(_1PxNwD^9mosbq~mrMQII;X{nC8)>RHfYzzI9 z5A*M;LRA(#|6j;hLF&`77_c1(RmYCrMhpX1$N=)jdiJk7;f>()i3Ldo{0lwNju0y^ zA5kKK;$tSrI$ra7WdyGwoMGqT{|bTrmszTc`>)J#8(TfL8{==|LbzQvE9D1OFOUoa zUK4HC)xW;-7oT1vz_aS|SfpfR-edQs&n&DE`YGZPk!x?>ypb^lcz;RLV7eha!{3S# z{B2EST>~{M;9a`$ra*lrvZ`M*Ad>sP;zft`h=wL2J)IQW2S69X+uDSw1X5pOJb#JpbKo2aOzHCM&M)r80#1^C);!Al+hUPlTky>D;}F|^sH z0`cvDXIMI1jqHhc5jtA4EdD3>(V*NVE-Cq*wcTKf5&ySNJ6zza$h^wRn5h0;fV_SC zcAKqM%GI&&Or<(lx8s?txi~dt5bL}T&C%jl*ENC)(g?DABld|pg@$Ci&{iRG*w5yX zDkNTKdo@7EP3ayzdR)i|4m~p?Lzo+k0T^?k!FeGKlG+EG7o#U`>}HR`DnC8YKR>xW zSyQSYAyLSA&r{p65c4BHBGOc4dlg-P+=WNU9;ui-o7|s|LM}Y~cGX^a(dnA8i2sYn zk35>28%Tv4P)JygO29O2Rl_&L5`{mmV=A?UO^;wum>RnWMxbP|iUQ(=8~F1slTmT=8<%px=@Kd?`EW3Uq!H;RM>!svct2QEq3l;@GuU~5D| zf@xuO_d^wVFze{JV1RF|m?4Z$sQ|~^PXLn6J1^dk!0r2za<`-v8W5mmJT$@3)phf7 zU)k(n(bzN?l-lp#zrS-IcnJfQ>FhGoFIg<^5M^>#oydR0ML=5H3O@u!eae#dbx<}c z^KRDC&c5pr%Vr+0XJ8;?ms`)Cz`qTP>Tw24i|@Y@Y# zwtM@Y=cgBa3?(#xE75e62PySv>@4;y2nX8ASZ=^_sQLJcl^G)UU4cIc-Kmk#xYky* z@y2IjP!nVUv5FvEu_!sD_G&0-X=yb!)eyxLu&l~L)3xSBWe9(-I$zL0fTGJT(8M!; zV|fZ|BE5qOAB&Wc9iv=D4B6RMwbespaaHPGP7pzmhyp62tG^#;3_ZZmQ}CIvNO>Z2 z>-WpJ;^iqvO!ykwE&tP51rm}!>K8-Y)_l}!W%U2C01^M(W0IRUUWXf0w*PR+g_O?n zS|#2?MB!a#@pB`QjI4eYdnl=-#P6mg0!jLLw*2Y6w1Bu8H*j*Y*g-+lms@R=tfkH1 zwTB4G;6*;9O%l35LIWw442oXZI|ji|7;&4Dv&+$Kgto;DKiA0UXuyt^CkGHs0M=_; z+_~*D(VxsLg9ua3tB@3mDFAsx?Jo@A9L=M6WMFX0|K|#B3i=4Xyouy32-V?o{qTeU zp_OOx&mfU}M7|9{BIn`JY|z5QA*ossYI8)SY+cd_KQ>YgP^K*-XC1XfCNX+j+Q_Y) zh=RzgR97U{dJR2J3k47;|AA})2ym80{rnja&@cQiT(SK9h=t)LX<^dvq$D!H<5)?7 zm)+I04HEZucdKx>Ig>g{thBn zQu-PYw9WxcaR-@q0I{H^CIQtMrZYf@$f8X*KZ;XnI>rVr+C70EH5fS_hs!}no0Z`ar<R@@j<}{6w3WjNE~7; zn>F<^C9`^%2Y7MoyHqV4-PG46%Mkfld46fBcmJAOv<7IQRhqxPyerFhZg!rI z+f^_*px}JbSg^X2?saa0BbB>L{9Ew8mkS;IrUT>_>Kkd(;Qf6TDk`cp(za;sD2C?U zcn$W26*VG3?TU3Ym@f-@<36?O(Hu%Y1>do-idx0Qq-v2_JAqHlTD$3TWQ1&inaUe` z_1iw*W^%nX?DZ|)=vur5!zqrVf@?fLdp@nkI`Qmx1mDjpK^ri>`wpM%%MAMB@j}vC zBBw0~sHEdJR2Efkm?eLRC|`N{gu8Dequq78adm~@)#u*`tr;?0<2{mBfdd;BVCsd8 zw{HXF%E6@bS|&2ng0FhwtmBL|%9^_tX8z`ft7XG7(!%QcZlJ@?3d7#4BB~7o0WD8m z%Hjs@05eDcktWqA;@Sszqa4KSxx)O_aOUSq#`BVA;Of1a*fbhwqrpP^BOqBno+f1d^urQy*`bDEj>P12Px0`qUepIXPC} zf#+N5`EtwYHsdmD9%uB!XBPLI^Bas5!v@!C7T<+&SvGg|P6N+bn*k(_D=Y##X7DwO z8LBJuK890Binzw<=~ou)f2wl71GSc^&l5%M%Qc@Ale`$2|wV=G;N)QX1s8RNC-g2HA zvz!Nb1sjIzGcok%iq8v12K(va)qVT&xK}68X_Sk?L1Ml?3uIRzaZtAl^-yvsZ* z#ClngtoM+26~+=JVn;$nB?nTfG#kp3fwg-pJvr*43DRoIFV()@+3QtcQyM=9h4G=U z8(aM=x$=ZzJg|vbRfmCzfv=#rgxy%&7r&*)BU%4sz~8lir`chalZuY2vYq@MpJs8# z@k+wB-hsBKxRQaS@mPUzlvga>>^v{#sXR@^w{wk3mr9mdW6G|IrslFQ;XHHa#@d%d z`pW|!x9Zg|y-wV=NI)sD>D$rSvoxtVwHIUatcPsbq&^Tj^*65GXHRG+ z$6QrY1}x{wUBJlZ!UO#k`qky-(e?WC#qixK2wi;krRjJY1CcCmWrRFBsb@FRq;ANp z$yw6`?!aD3f_`JpoL%y`x;fiMYTJY2zUme2FzZF4#|$E~DBD&m#x`A_u4h;;if)a{ z?O8S)SAlAR?k-3biWXX0GdlnRZwXaYcj$WXqcXZgiK%XwzsXR+>YrHe}d zNAngh-~4V70dGM&Zo%d0zU}?TRymW7UtTrY*ql0K1^O0!vyl<2)tLy*S**jY(ubzQ zZB-V}OD(;1G-FuBc9ZLaQz7;9jz&%sEgDas*5TeDBiIdeZw>2D&p5t!wkD0j=3phl zsD@8^N|`y8@;OHg>b`$}uynva$0THl&!Hj1vz&qF*i#Q9p`vy982o^9iFD1`Vm!xv zg!K6n&5y{#)ZBh}Ro|vEBaCgIPX?W1Pp9a6h*eCrnO6r#PH#7;S0n|y4z2E-tQUoY z=0LT|3CD1`_)R?;`;Qu39Bhl3nq5Pra?bD%?%%VMxr zB$5p-jh+Ea-Xj%yLZ;r}G1QwPZ$idxWW#!V(POITwT#+B>YRNl_;QoVw;?o;m(7m| z9gd;3hBN2=RTFWo7(Bx5A@$`$&9t7UNpEZ>ms@om1Js&yCI(R%tPU6s2Dm(5-Om;X zP`=xs^mV!Tl-Sk)S6n`yiC;0I-o$qnRoEK~FBCo@x^|#9r);XF>Xslk=Z{lKc@&QCIjz!GF938+e{91r5jP81YO>lGj4Ho)S;trb zWxMM33f_XKgK#!g-m@Rr^6vcF@#}X^cR3ui35F{r#rDqo5?CXOn=V8vUVEK?JnUtb zjlvq&%59~Vn%eqW!CV&`cm??iLMmM3(l6(*FG&GL!cW@?pO1Jv0o zV+Lb-3e^Z`X$qr}Eze;Di^Z$i3|XzmA)?4AbM7$r+WoS8`*Nd9@2}$;7E_*Qho{@^ za~>}Xr&Hn;jiv<8Oe*7#Heq~ldvBFYRe1Edt8SZ9Ki1(pUHK9;pN29VWA7R$ozeM-mN_3}608MJw!vuGTrSx7<2a z9Y)8qd-5sodFiP|eK!+L>W_(x+=qAGPgkgkzSOf($VUeSy=nWYnRC`9#%~KfiQjKc zy~~>2F_)GMmc4|<8To&4&41$~vkKcH0bURL-XW%AC353M`2gpv!rp{RncSS)9)YvN z)}D-F?A3DyFvwwmxt?BaztKoNgtBmPz}clp)o~dohO;FOU@6(tuxC>@Il&me1qIB{ z-|ug};~P`(JZjHd0cc$IL~5cFDdQ_01iUsVB)zz*eEY|r9e4opM%ck*C}T+C_Myt} z@YwLMNXdnPmNq<^PF=!8EgoCm5?oYGm!N&zL{AOFZQ$hn+TGo~oVf6X-F-2O>{#wk6L9+-MxHo_EkyK*lai z{k%BS)W3&^AsspE&{yghg8F_wYBn1%CWgJBRFnA}XT5y!cVHEA0% z+qbfPm+o%i#tT{4ykksTm5{Y|v#+cHpQ@1y`s67$F9mIgRIJ%uA{VPfBmLlsu2~GR z;+=QXmhbYU(k@@lI}LB9Us`_4cnL*+JSlGm)tQ-f>!P3Ii`w?F;bpk7Qs z*f3PyIdvc7sz!PZWt}^Yz52c**p~YG43|f61sKO^AUqnhh1*-oz&b17KN0G4>aT_) zI3SQsInes7>2H(sk#zr(w-6Vm}VDn%KBhP&0 zc-ACMF&+ur3s99)MDsQE4T)6Nb{!5b%_o`=v#Lh<+>Ly4o5Nx1u7E#qf^y!GY1iu=ZmkH>Qdj(Grr@Z98} zQ4!q+g*OlFv^V~sBAAeC4u7RVYj!z22nF=1MGNrF?q#EMQOJw3Pg?OMQqB4FU`VO4LldyMXLboHh51THbc=*WLu^Y>e$iOmhXIS$y z$sq#_{${FhwyvA1dzEuVRg(-h+l|K@avJxbn>VJ(D>CfbPvhu0QdUN7DgL$Tf}=brQ3*NCDvbNbm-hyq z?xj5Y;XxVZ)9Yt3)edYD;5KPnmvt1B4g2hzm>@Ng8Z+xB%^|JOfs%S>e)GX2!c zmT=c*G8-s-l)PhEcCH#G66ifcb9~Wu|3zO-iijgrpu?=|V(VGxsbkyuEN5{cl?>M+ ze)$vuxs|r3(f9Xdr(5;yTWX6o(gF||kEQ2xuKV_T{?s9BMHXL+PQCze+b4AM^OoPF ziaxCTOndR&i3X|t++2_R=kBC9By6iBgQX$T@zhgQJXg&`o;9kzHh4U@dJr0f z0vn&q352T2@zbCwu+?6wHI)&!1ydUI%)(|29Y#&A8QMSL`TiJ;J&1mn)Du#;NmlVz zcw@<-?qAt~V1hE$o(Lk$9v?Bv1ou1>`N75xjzIaB($u-gHc^=1kdNBg$nn|%~ z4-K2H$E)`YG7p5VUn|7q5}vB$QaYS;WpK40$v(|=vd4j>JJ`_CY8-jp>Z8MKYg59r zM$bPem|hrFUQtw&7Qj?eQ+sGWRmI-%7M&ZoN!=eG9|knQF8rAEzC{_xO}80Q+;N=> zKiBqHX05eo>pM)NF67j)tk}*zRSj;ss2w|?oNP5cSCt2&4Pvx`zYtUHo4W;*ZZ0vJ zlDeM)OFiBS8`mbwPExYi!Vr`Kfjb7b)umbr(e>X@f<29s-k8QB zxs9>T0G#=owRhmoYYteJxSlMjL~UzKbXj$nkd>Os{>nCguRHN|v~N5=5~#c@^h^ITXPJk_aoS04b4;l|5rA>PTXqGO_Pa^Z zngTP_zuOk}V+p7~=k1+qtL@Zjy3EKJoaxu%NWm?VdU*u>sXPDc%waGsTIvr*Supyv zz)!R1@BSn zW_^G5Is|xt0T}o1R_3JrSoo$i80#5U-cZYI5pauvAE;DzMiGL9@K+w1b=d?qetgLf zRQtP3t2e6kJRC*+mHnR4t|W~$4(*Rc9l?Y^E6u8ElJimB>n4qg@t$S|PwuvVY5^R~ z56@T2>n3oIJn^ye!@qsd{Oz7tRQ1!`O&8Kn%!{*Uglq}ZX?MLKQO2eJ9g}@)i#kt^ z#%OQSq-SU-ndkqQ8Z%S@?7?s|-&nIyHIh%+v-)P}C^lnD=1mF`D&R^Q?k*TsMwtYn zgj5Rm7eOf{&dKq_wLBf0AMu&ERTxOFD(rXDpgo&9GRpVyIFZ^LFV-<^tZ8=om1Izf z7`aHC5LHeAgOA2RgjFL<&73V0)zcH*cVf2IBTjTFMw3aR4bQN zcK{LC=UVkKDy)OlI3cnxEI+4vS3mD4$vVr2r?$kz+43zMC@h{nS~3^z`J#SaV>WK( zGf@a10ggb$!S##-Nxp;@Vn5_!olPscK{6;XK#>LrFQFW$|+ZrbsZ%s>Hp-}$pLX=#o*E_hQ@$M+`}!;)B{VeN(5 z0$8xm$r}Lj6S>qqIJ*drIjhU7CpxV^UN^P;;+r9+N{7T?x4LoQ`z)t@Z_-7JoTSDTHxPuhP#v+8iPc><< z3a?t@2I^UHw`FmwdgI2NSgQ-&U?!DwF(9w=Id`N8s!qNaSevi}4^?+pQN}_9Jzb z4XPm8*~8uco~gW6`2$rF@%jC!dX5rd<)|Txh`$bV(ZnMh*tQ3<1^rYlGrz>nw>Hr3G)u~P=aN~k!>sLhP z2+19(jJ6;Vw~7mYH->(meMMaBt*E}G+F~7zEW0(=D$s}FZgAF~axS;G?KWOJdI#1l z{*ZH#*ih#p-=ngGvXIc~eAk@(?F@S%hx}Bh8^)H~=^=0bX_2?SUt7?U;l{1Yu~Fv7 z^s(EC0m1nNjRCV#jTA}0(k~?1fsA+MSASNG`AhS>BbZHh&uldlTpJxpz^nB@MM;~QZ*yiCxJ(y*&jySKiPq_l23o^~15cr^JV_gUJF_?8$=iKa5e3Y&B@wELvdMX~NIv-4zcwUx>s;bKo!mZE=x7Og`nTPjnP zH0ZkRpB9SIK`aBo&5y z|I|wRU(5LdNyxC}(dQ?U-96Hv^~7-m=mH#Ym`$#=6M2NE8_RV)$e$EaQt)Gzi`bsw zN@zYPG702H+g;w+U+S%%4Ra|>{RZbhe_9z(Rlhn`T}`$22)t_v0Nwx}IJDuiMZBnT z$zuZggL)WRXi8~pro?F_2c=V|<#o|AQvTUgU?1Y*Dyd2s_i~~jUYq5o57o2>FU*2* zZnn70$uS=T-7%2BHUO8+10e;PT=)L^2E1@=*VCviohkcmoKw8Nz^s+>?{|QdG+e;w<1+Tg0#{{F`*;cpKNP)P3l4d-q(+#ZTCNExS@|%Km|7exUT5 zEbNu!sgVlHK|=0Q&^+^X8;|dN6%*HWcgbLELtK;GFwy;s?Vl=9Xw}I8^j5w4=SFS* z%1=@$`!13WN7<5)?Jch2vn35r$i;<~oO+|6FvKv~IuB%P4G3uJyH68xyc>!kUpF14 zelVZ99D-OO{b=kKx~%bdt5)H6LY8i4S@95DL+ncR)@4PE(vX(_&TjyU7)S`PDv{xZ z|0`wUw~gX*)#|#SRCKNoQmHJ8>;qRbxxlJx`XyUVO~wMPt<}3z{``kY)SKZa_#o|} zzpQ=#>HK{7F{bN4Gn$;NY|+~5J_p_q{cd;6#$8Z|HbQXX$K@&mBA~j&TnK-3g3go5 zY7Ixl`UNO{OwCa@)IF39TwzrPXL1VYf zN3lzWLBm48D}SRTzG;0G$A3reZmTdvhz@Y;qLm&&VREc6)m*e)IbITt4~cnz4E;gX z;lEer{_gOS|C5CMad~}22|!Baz`^n&3YDa)i4*F7rC^lGtT3r-(tFK2PQCU z@euYO*_d311SIh69+E)B|0EnxiFZ#}&;&*OIb0QMpI?W%WP&`A|AzuZRLE%31P{D= zB@hAPZB%5zo1GlsIDmxQfr8);F0(47Q;S*Wwvzspws z@6R9}NMQFxIkf=bOaZ>v&y{@%uQBi<2tuVIwEvDf{`swE{GXs&CAW|fl$UbR1R?3m zXMNXFKAZoOIf0(dC-;C_*4mmeXz&&i^{;VNuYGZ?bwiNWNBjN%p_^DiCjzfL@<4)5 z^B(f<(FlQsE1L$U9?Q!=r{erf43s_#HJ|)f=l1u%&WeWo2N)RtoK&sCFA(=XQcWf` zFth9M3yJCf>>L(}(C-qE+XwWo#AIf+9^Vxz&|%oyAj%hEC==a3sBuNR-fkeMZlD7o z3rR9<1_5>SCLRtCSJ)z@P-6YSynQ*cc3=Ed}DZltnJ~>CQMMp}OCk;I( z5o8Ft0%rdEFucDdDcQ9+2E7c=L@nOb><>U+^!tuv3X+kLA-o{X7o}pOSeB6lcxSCK z;ZI$N)ULA^NJS@TA#evt$Ayj?+^iCX)f7NG=UrHZ*@V3OFp@Xfsv_zil^>wLl=pu3 zEIiXXBhuL=gX3Dlt_T@VESdoQtvd9f7i6M%Sz|Ex#y==6)b7pwCWm1VKtM*vmt0iI zrxr0b#@%8>^g_{suOVvq+Va+B)l= z)8o8Wd9+|gKnd;V+v~LO5Q}{)x*fJI7f!)_tXnnO{PQ2B+sy1!Amh*2L@l(sr3&=F z5vrxiY!PGN>2t&M9 zP_E&iZlJCggTAzmdwSrI%Yz%_Ni1^F7?sF*9TSiC5At+2>uo`_>&D%D0*Left5(#3>*TiaSp3UA6KvBm;x4qV11HD>8zrAFzND6|V zD*Al2bPV0UR#)2%abkY{=M$Wqz_}P3QwgGp`(E8eisTi4RYB2LzUA-rN(99-6)B{( z;|$6x`P?0y*J#!O!A9iAsx~xKpa+L4=>Gx_`+x7mfB6&8Wdm9TuV0v{>t^QU05bbs zERywM^hM1pYFq!X)5Pk;1z03rKwqqI^eIxnG~G${8m12nX*wlM#Ui;!`UqUK*RE7l z;gN|Vko2Z$p1%J)CF@`BA@#jQKhTF>p0D)iJA-yH2u(#vNB?i!`EU7T0&Wn{?U-hz z3cM!>M1iyh=v_UvTHp}B&NYC1eUU2Y{~a{3blp=GL`(TlK=QZ35N=XTjEXhG^aSkIcpc{kx*!!i&tC)G zF9)nSw*buiy@W231RGX7BxeWOePa>WIgpSjlxU9UW zfzOLn9la0QGFdnK46b!Z1m2!O1{#EcA8Of5{i7W!Y#O+=&}W5xy;W0sT6uy-9LN(7 zlRPY+9Z>3#{c;71`k!ZgN)ssl{llSv!5YBjn!Ag0{Ois6&$eKk^akj3j-_*NhCXXY zb|&6>-qj-nx`43>5|ggA>wkF`QbGO+$AL!VOxCv1)|LAI{K$Wa_U2MBk#eG5UjBNw zP(ZF^m(S|!N8HNa-W_(WzyH=0DY{Z105A?xCD7fANNMB_+0Q*k;cz!-d5}S>*b^wB zt{9o=9zH~>k0aqz1|xeyDw06{pe#ba=ly4ga7F(zg*4GzJ#);meps?NybjI{ohW13 z-?G&yUY7SW}ucxfI_LD&7U7P&IUzy7JR_ zHs1mn_j3})H(zi*^LBJz;)MPft%=`jCi^_C7X!8Nx-b>C(O46_f^- zIT@PIZEDxM!VSK|0XLyyNN*9nV`U``((&r;CE`MUy$+xE2cLS`E6M1F@55~muUuT{ z45~qEf8^?_QD+Q8ioGe-;~h`PXNmI6%krB`-#oq7ngZsryAF&a;*Moh);1kXmOUAo zr{_71KR=Fm{ZYc@J`TN}D2Hecp;4ut!6pFsh+in!5#bXYOL9fx}cI;T2; zP|W<@r|M01pOwUOYTWQfue3V?RZsj=;;gvHe3TxMfnk&naJe+aT7yo-8Q$qlzs!Zd zP4cj#y`!)FQNX`P<0QC8+REEa+MwOyV%?O+>V;bHGrsq3m-b7`36^DYEmzC4cT}M; z8?;L8#y*XBG{4vx;fag3JCQdc4{y1ht1Xl!gd>$7O_yo6w(*>nR+`QH6pT?PBs)90 zn8(eJ1GH&%syYKsM=Q7@sRjA z2gl2sB=Icf^hC5L17xlnbW8f@$10gtX+p_I{FmnnCL=`*I&K%0Ic@_|{oNTsM7v;{ zH%1F%Zrz7QZ1JDJaB+ZzdEL4%si(+Tn=!OC>Jjyvg{75ny#RE^IN~zeRFoIvYjHVN zc+u^3ujsgvbjNs*nvNDkOgq_hS7u2{Y)!Ieez2=BY}f|(HoUm`q|KPYWdU8jURegS zr_^RCXK!~%zswYF@tI0nvnz^*hSgLt=Iw@PPIUnos*2rI{mT7#SA3%0u=okR{5Th% zI$=$7-n3B?e}-sxC@tdc=fejyi#aI{9iHBI7VAulD}(9C#&jH$G_5~X2mUD1s@I$L zktnl-@x`%UqW7;=(sp8z%LQ3Ni-Mj|X^syUa~pOy%j8Fg)2Ps^9U$I2IkpIKx*nJC zj5KOwGn0Uc+dpg8nDe!gr=2oY^%!fXsVU#&ILOp4hD*uM)YtzWFV)?fP5)W;{-@-L zvEP!zT_54ibLcGUVxNC&;l(LDTX$%-K%>`$P9M)fQV0kpfk=!&YOy(m* z9|SA_t4unCPNymH_>7Op{cBSswS5rhif>Rtf#YGFZSQ@C8iC~1A+?H3Uw3}cGl+9o zvlvclb8$E(ap8=SjsGgMpUZOARjtxF=)?e6456+_Ds!gNRc>4!z1U~G4!>%X-2+Z7 z#~nF`9p_y5j;=DZ#4C4=j03-ZeF0`O65k|o&=CBKeMXaHBw?b)y;9TFx zKC99@tWqsYhs$f?lOscENn|?PC9UbgrOA!g5SsWb#pJO@x!kl)VYF#x2W2;Zq~}c? zmWZ9?;AY2pu?91l7h{KZtd@gq(oIuALHMkZ;&^PKc$I_|2|T9geNQ=URP+9V5M=fb zSE$*Z9F!|1>rQiH(I|($QO*smpg3fGk%15n$?VGe%_kl~5wui$gH6E!@3UoQSU?_h&}pmtPW`CHo=tdVRaZ>$u>%iU^n3;n|Jr9scD z+Ff5Jhlp}*U~GAYYI08yiEYj7EIaR8OGxAoJ>!#$aFU6Ld*k`mE0Tg7=Mn?auZqYz zO2ND`Qs9KCg3^?T4(==qmX?+(yL@r_T2oW=?9A#Yh?1f=d|U3Q!m+nb%8b&f>4FWv}gJO4gtEjGAsbgFtk;_w@8WSg%nN`DHw)R!kz^MO0;gXaUn zhk8ewwS7-L@VO?;E~$0S+-{OkL!JCOU;NgX{oz&=&zj#|!usp$079pt{n3SamBr1g zvMGUJ?ATmfk^-mGot>A=)p%B(5MkekF^{ZgB`&L>@i2JITAW*i`e~Yd!oy_g2S=p{ z3iC=iDXbnBIyL&bRZ`|(I>bJ1!3U%2)bHC4hV>z?H%W%LM`z&68@7cuclBk4cNZu# z&Fh16ncl1}Rz>TN*B$07MjSN3OATS#xe6<3(sxi-Kh-;Kyziniy8UI;d@`rbH+T>& zsifrPOk}1HE(O}6>#5-rG{&V7<2`ApVeiF+$3ZfzY<5_X=7+DP1U5mr&ChmO-_VL_ zmJiuRrRmBBzB0K?c16F?t2J6IYrnxt#?{vw~83FnfEqgE zlJtCH+Rc%JC8x(RZe}?Lah19M5OZN4HU+clsWVbOZ93F1yqTNTzmJ za!h`4og{W+vnqvj;wBY5^$s6ZRlzp68tSg1UcL3UYKy;6qw=NxQ=64OI=mN* zHouIVoMPF9JHj!r*3Te_nPTAtwU;RKMvHzs9+_ z)Xl&y6_q!#rB$BH@vcD81CCANg zToLw4Dsk1xZZ~FEfH}a(38Hmg8{|YTYcj^AbZ;II>O#jU>$=lHtLcY}447kYUX-$N z7$m1qRq?K&2D>_ohxBcpsj*=Ln4UpFGmM$p6Qb^$(bWj=@C6N@-+elBy`CZ6qjWsS z==7Incp+G8vf9zMLk9d23 z5_~sVt75Ijq0Hq0+f^HlpIy0Sv;|s?-%&M zL526=w>F=e!7cQ20;4(0_tQGWt+jh&@N&IfA%&tJZXs*t?G9@cw#$9{58|R&6sVO8 z<|+zxngt&cagySw>I;zWiN8tP2u2UUMFsXjyg&b%5I&wU`!AbOfMQ>ab zF&6cCzi~H+4tY74buZjfaBm6yDpZgX3&DG*BL>9Xb0V87(?LWO&nVihyZV^jrs4tU z-!q%?sL%_#{h$^Hooi?g2R{GMha@!Oc$2qRmTSjE#rWW6M%2<3+i?Uw(MYUq6vyCqMMj5{7r$a{ zOGz-0exY&XtEej;?EG`T_vCiH9z{(HpRqyP=@}pMJ)c-E{d6O22wcA0fmd!PFdBWL z&M5+SPh>1dZ*-G$`?oUjz#1`8z3xPr93b5iRyy`h0y9qm`(`VDWuijde&2|=wPKB# zyi7H7@$P-h!b->!FhHs@C)O_@U_V-@$)e+zWKCPd0ogZZ(Mffp7Hf7B@k?>sISlSS+=my+Ndx{RbARH5T~X!%kx zIX(-7gr>X6t@+hY$tYgIdx+pMdE6j;_DHru4Nh{p^V$>cQJn6h$r+Qu%>J68URz+CYyvkVU1E57uO%EKiEn0ncY&?H$#`nFe0r~Wig#;U zz@ORaPI5%ql|zVbkc5VY5`zhS*?0o4U%#HaB_y55A$p4Op>My8iCLm}=>g(&gMo&n zRj3rv9l>3FD0PAVQ^(vnr)^jyJejB*h+6$f@M>uB_O5az>hl1 z@X+4m{bJoixXd!4I2To*keu^|xNQZFW=ZKV+@E#&5lJ}s`1$rv9f|vn&COf?*d*IE z7>v(t$^kY@N5I8PLZe)8uq9ckbJEAH*F$4%^ZOIdslAlF03JHQWOY=IOA?}r33K{w z3N`be_`#Cmaig}gC*%;HWiPhY`}wBJ$YFA$OV*}LbzMR$0a_Zt1} zWX@ljj?z*o7sM|1CXDsK?`Vqo2PN>u+{qi+YoP6oFVWj|>0{XEO&aY3mW5(0hHAx_ z9z_2=9_Ce48xY(rI@?sWXDkWcuyk^|ii%GzY9P;TZGF}5 z!I6Vt{<&BX-iY3hHW~RsXY=}rf)tN!HKzhKOgRlP?zp=?JC4mOL;M*oRc9eY{O>^A z{G-J%rEo72QrbSg(bUgluJ3DP+@@IkyEi^fkl@tKph8n4FY@l!(sq4{8WI}aesN-v zvxlYWo_yOtu)8UAXUEDh;`oex6CW+@&N;AQwU8?ZB|;#`2$h1Ot%ujw#|Kqg49!g{ zYP&(a%KWTv|GP8KhzytG`kZmOWAgUQSRU?UOIW=980GscjWN~oEf>BE^0U**l&tt~ zBNE$(_-xL7x^f2wEQ4l5c16rWtM;xbIW5A6`o|?LM|65MNAQ3PZt5BO&v%D;+f7o1 zXPnV_%q<%b@e0|`fwy!nfn6j^dGz-hyc3uDU^ZSNfy7NXZC9Lv8xEuQ_9mzGB7V+g zC(wL2{iStLUbomPfaalZI`4}Sb$Up2z=Qbc$e6Ti?qmx&y1Tx{Zp{$I^ng*ZFhr1W>Dg9&ruw06w z!*5YEe9>P!UfBkd2>W&W*StyI=bgB?yY_gh)7Zsw@NDnH{%Bv5g<`Hvh;$OuV1<5; zfIp7*Guq-n+?Cof3~UBFlqVGnb1lL{bHBy*hJy*@O9TX|UeA%{YM#i_#AY^f78z_g zgYh9;{hZm2ToT)jaEqKm`-G#tBkuc&ZZpT*Q*_}|)ZFRa%e@+);UX{2{4At6zbZw} zh7_XSI)TbG= zY|;KAF5W#4haRGiASVOtg(``WsuXG342t4N02C_Iz8jlR11jKu4+}wQYd}7pb6CL4 z%$5PO9a>b$(z*0Z-Z!XZX#;%staoIVqoG2d=%eG9v%3z*bPW3%cN#^98btB??d{ru zcg2Shk8~RU3;y~?*yjKK$MYE-7^j$?o-S=12qtA)&$r%nIu4`Awi8shlq$dXjKgZc zvRd{C{voe^7yx(B?k&f}PYorZl*?A_zlfGjW*V6>@A@1_#64N@vz_u)h_)Ng1>TD^LDm>8=g+RY zKMipCt;08`YrC13BlL+RcjpIXr?ebZu+U?z7+6h}V}x*YXhEhNO8V(Ow^kf(!XVs< z4TU6_h@XC`OC{9p%-wpscXr@oXhwT*wzEY&^r6qd1+&|oBTlue3ef^@(Z+E}zJLFY z!cOMXl$YW$O9etZDckp~g<}(q8aT{U1W%qU;?BdyHj{7garg7X3wTC14~n78@kUh` zaGbY0zr*2+UE$=tkc-L&gvqS7WK^BltOtz1WlRmKTv}!ZM%frb+0ovuc9Ti7Junow zjnDPwV$d%@IvU00t3l_08G4)+i>{{uy%hs{BpuB0y=J>>sc~Vaf9ljqw@z`?Y`ESn ze~_Y(HIn3>&bqo4P1`A`4Hw~(u?+iKhDzjlYoenQxxdmTU~)OqluKyL zPFB=c|~fIJm||gy{P@H1QO`Nv%OVQNKx&-ci*59B0f(EFeA_ zZ#+AaNMIvi!g}!Lu!)+>?ZdwwT~6a#J_j7u4`863DJ7Yd*? z<~ZWeMn)G-PE@a`ndSyAX2#j{H^N;eXFMU3*4ZF#v$;BM6Tc7UtV>Bt2eOLeze^@d zy-9L#S1y@{3Ls=Lam<*#nf1-pIn6a56}x2eRhvPGI$rbcnBq|D1&f5E|sdIfmFa&8lt$IAXrfPd&8?BkR0(r_)%} z)6~4qcJRorRv5noBIE8#FxjsMDq3*KLQT((%tddK2nh>M`*BU3$~5lGzdiY|#*`z& zzCM;uV@;-gRH4rT%;zx3g`yeQUm?yuyB7{ zG(v>J2l;+cRYBX5%pphJP~rAOy^4dz3de`lP%xw^ zNd?C|#h4?ID6%Oi_S}0BMHU!}^b+1-H z90-Jfk#ZCeAt_xjESMck>|2qU10^B(qVr3UvF$A9%Co}9)a)9#jEG3&t?W&xuBjK5 zswgzqxf_9-!hdfj$6T)**j0=mOaPAm>U{=v`$_ganSGViE zx=4SF$>Fq@31-krC@Mx889!hWI#x(Wzk%9U`%R92E7W*+L4PSHrBg-6O}|TDL}W2S zKC38fqqttSsP>dPSEabfXdMsxDil_Lm={c=PVYY2_FcQyFV_avR<2MgQ0V!QDqU)8aYAgh8m*@iR!?grlQ3Q#> z9AKaX2G&-jSqrL2k%17;o%c?+uiRV^w;}S8Ndy;{Iw>ibbxZcA$ZG#(*FPZOthjDx z`l^ln!ygE}c?&SK02Uc8;Q#D+yGH*y4~FbK0t0rRllg?)t-sz=gl`%2B~mdmGKMqg z@JZ?}4mft0U*-7!l*K=ihlYoff)47(SXkum-n|25e$v0u{2M^(@#ekj5gj@hQPlB- zZ<4T(p#saYTxp$gt@oazN&QR&9tmP$e}6Pi>v>dM64$URbDKZ!iIu({Te9q#^Qu(~5uhnLJrg zD_F#U1zPM+NfGd82{gJEr`z)xG1yq3ElCcBKt%v>@-bT2%~{;)s~b{~>s>=L67!FZ zeR>xIBL);rBy}@&MRBgRQF^wXKxH2jEsRo*@b1Hh6cEycW(Et4f48##=VwF6O-4dP zEVpqVzjy@%1-+Io#Zis)KvCJrq`onQFF4*^D|$L$eXSfMrsJHWyWh39sD z|0sL=n{=YyvG`Z6g48`6YCAUBZq9$Vl7Iafal&1rc|W8}({89)>`T%B#|DL)taY+- zLvLbFPH&;DUw>qM1X+EiQrV`cO_MgR&EHFs2l$ua78Ww3n<%r-=hWF!XU&@Rw(py) zz1*PW0{)Cvr%A}5KaNJnVwRL2ahzdf9z!D;8TtjwGQto4S4>C8`y1UX@XC|DQ+!LV zewC89g1C%k{^c;s3|ljmlM4_fsd%3rW{L%wAbf9`O@*fY&=;A0vF{2Rcq2}Vd;1Q` zDf;8dESvX>aEqaUD&NTLMthYYh``+Wec)%~hMxZZ{rmB=XU}4RKeXmMjk0Dk+8MC> zR`-rQVFAU%&csUf)i8_ zQg?&&gH@+>mCZ+wPV_dGW!7e#tG3RLrp)CF#mqUa=H6y+mm2i0GaW^RQH)4rKkT^S zU1fG5xm^oKC^}A-3TuGcbFSi+!w(N$$oq>^^r6nKFQtb4gftn#M8*dlKiFh^O;Jdg zp1=Q_RrMcD?t~;UBjaFX8@QM^)bMl<*DK}gx7TPf)Dh`Q-ODyp=9dv^a| z86MhDj4{*$&78xvJ?3N{O33`C`$~H-0VeCnCianhdg~H}(UST`lF5W$Kc5D9hFC~t zeXsLCK!0aO2-{x8(qd8?LrCavGO=uDA0$RonXe)V=3wXXnI9M55gLDicae3O(cL9P zETUZTG~mC#`nP6=(8NUAzm1=yk&)3{RNGT__w)y@+oIymTkBXho#ZhbXLVsbronbw z4yR)W#!q{oYyh~|^s#DsseiMeR#OSz(J&w__=pqFM#Ys|d6Qmk^XLeDp$Aj(Ru`J!3 zBgdr~y;ZkAXJUP>v5B;a=F(D5LMPFMc+%6LP&xM{sh(a#OY6YPQU zbn!>&q70aHlsn*+74|K&^6zLZFRfFnCt@ zVahz+^VS-jx&<&Utb2!`5MJDTL5~+`y%5BH%qt5W`wqwM+|_OGrGgc>`Yl$=mzY5j z-UX^BxnH-URH7sAUDhkHkWv+j7CUucTEqY>D2@aVt;~GNv2SN=nWDR}I@0lI244*w z$YcBnV4!~i>SA(8>^*<1fO(8oVcEGh>%7+;Hs)sbXhUnG2G$IKkk5@FyJY7g5woc5UPM?I9^8DCTUPU2^;p_vvc{EShQ)Pnwu9K?Mlv zJu8*WGIT9GhEE7le)x{maAL?FJX{$|0+5!`yJHFPuBP?za_LZ3KP-wwEBrG69vZmVO zt8Icy*(*>xhZ~)b-DF(?8;kbmgu%RUyz=}O3>y9u)q77kc;hTWhV5Nly$)7K+Kut{ zB@=%YDGhIW9PG*)|Eh@_hPTXr+B;q-)H}oA=P<8J>u1#;@=^4}p3EWVI&cEBU?+nmb%o{RBm$%|C)Z7I{4Qkx7!{|vMgV9_cE>fT-+~$*t6XHR9AR_5g+@& zjXv5|Fk!p+xhTgw9*GTNs?If0UcfJoH1=owI!*VrW3=Vq681!Lc5AfaA%syXZHcFd z!;5wMneI4uj3(F{sk%UX<}SCpRacUw?t`>M2w+cstMN+wAnF+Xa)$#80>QzF`J|xV zpJoe+aun)Y_4)Ekgt$Dbx2WW6N@gOr)tOmYEGOD5AwF)YvOSc2iQ93JG7JzQ%5NL& zubMT50RUVOc!$Bo3-ti!WW;pTo(W}q%&~X|ZUb=GIy*OcgZ?Ag^Sa`ksnh#Mz+F3d z-JXu`b<;JoJK1Yj>?faC+oa;2{659Q3+pqjFF+PZevI%fffPM2Z5Pgl)( z17-WOK7e+h1^2dXXKeemD4u>N2n~;OOzr1!QTB=;_|6XAX_)nE3p71T4GHC2W`9ET z^HE|_$}sw^xgg#Tb2%YC2{OH#*UK><_GJy{cHCCX;fnwmA0_vF(L78I^v0BJlC7yq z>$+)}4s4jcqvfH`aVxdd{=ko*q=j?yuS)XYA4Cia_uJa%4)v9cgYk{PXCrF|H>d-! z=>Rv9Fxs_bz^oqD3EqWS;8#9$AaEZp?wz#x78BG8%6EBd`isXLJ&FtT7cm*riLG;I%+9BlLKLy{ZGf&U(!&0kTV zC~V3;CSr5VG!%0AQK!_m=&0@q(ec<1Qf%7bTXE$oojm;9r+nKpK&I0dM~Ca8`=l>v zQYs{;E}>LiU8uj-X&-w<^`g>wZD=g63`IdZX}MyfT&B8Aag|YBXaQ(7L<3+iTZb~6 zQikJj<7jpM4aI#=+thyF=o^FI?z;@`vl&l!oC|quo9^qK2F5wWbb6%Y9j;AfywAZ6&k=iM*M(&t!2_H-xXb)*jW6p1Xwgg|A*Du=5=y*ps z{l=5w>~@!JSm(CftC(@wW%+frLT3WX5@E`cGrr*|J@)a_kuj#XbNhXc%T3v!G@C39 z6^;lD0PUq0CMZ`_RXwXdd&>Ui6&~+i z$x7YTM6l&sNPJ7oAJEqB7#Kgu8qjfNFYl5#Mlj774Cw^3n;evMN~b;|IkGw4c~?8% zWxA#1RCUQbRQ7YBuSwQt))sbCR_)VDiiN+!7vGKyP@i5rd3Es#RR1`!`?EUMlO8Hw~u55H^F&njI*hr zX@}-r(e)#DzYR!}W{5jc!VZs_(S3I4JWKVvm1}dlZaSNk*LXX)LOsA_%!0?X1UwTm zfR|k+S@fV9gMCTpSC{rFMoF2DG!NE!s=293@yjI@z7ntJfYEG$5fQ@g3Z=T0q0bgy zZM1OUR`)(vL=2nxY}>`ASpm9#V(?<{F&mvm5s5ob7lKja;WI&+-pD+vP@#;!t75+2>%TM6rH|woO#bLS zjbhZ*U;N5wQ14I}pMK+BT_zUV;IDffstq4L;|?SFq_bOh%grx2oe#c7Hl-ytn#!M< zrnc4WV(QP?GQ>Mvke`c7VSjFV=`v_`yHgqRNo#a*)&=(HBC3)8k_GaeuiB*$6XpWn zX7$9~;%?>A0vQ#<55J@?gWt(^qc=82-Pfr^_kg6nhFiBzK9al@bod z!pE|qXCA*FcBU*5fJwl50kKcCy(R{H{(&LNrS232{oyp;!MhkLcBJpDC|N=4TJfmkqQv+oia3?ys1!EteV6g^s~9-A>ORy`}P zt(}mtnK5L65x+O|55t_|3BtQ zfB(Wt3?OJ^fU$5szz+&bW?2jEaT1pJGGJ@HO=ro#eP>B(k>Rb*X;)cZ3R=`RmJL_z%&;$=ZWP-dxv{(6ln=*T05jAr z_X(CKET@_x8cvp{vU}Yyn&PmKWlF#yb#eL!DL{c7t74{4V6aZcWg|gtjxc_^%0Osf zkGv`3bXYs-IegZodPNof9B~t_5+#Az&UF#*l)0#s;e>WaVAx)9Kzl#2hcdfr4Cv%D=UVx7Xbw86S zVpzCPa&ul8Zla2450G^=T|=cyOAWA$Lm7_kOYs2v0rZ#r4cv}*GD3zq&vKCrCGh!< zB&sgo-V#zQFoQ_~HZ!-wIc@bh%)#(HfZ;)8whSKk8G>zk;@)=c3Vj@(eHrdDK3eHg zH+s7LyXgSS+%G zA03Y^dZ}9_cE%ZFG%UyoFP z5sW##z<}wOJa>X~yEC?Qp|=+K(L5shJ`GKDbiqUWj90Jf>-2np%0eb$XIBv=!T()R z3GJ%@8v5!h>3H(f`*vE?=P>2k`7e)iU%3u%O*K!C%A=l2xoNQ|wC=>n{pd(Y;{0EUcE*cj1TuBq~ChS@#&Dzdq6bEW|ik2$^LMu!`D_Z*w!I~#BpOlKb&Q)ya=(0 zS-!yh@5aj@dDJ!v2oXvB54!0@T~h{L03t zP&YJ1f*q1wq>LN%Rzah6CQO;wr(RDOguN0gvINt9apt|xtO2*ji9&BCVqe|& z?O`5PIP{BlX$-H+5r-iDzxWx{m$=%+rV&1}#UnJmYz+oo8cDri97d+;oW+xf!vgtUM-2$BPn1_eO_xq$*Q z6)m?cTMHNAZbMMqZ=H=2WZEZQbl z$8!UE5ewkGc$XD#g+9wt3I&`P%UJLBW7N@w!XqW-9szS$5mjnm|R2^ zJMMlNHp(lLK*%5m-!@HA=2LBWUDUK*QCv6s|55hVaZ#>q+o%EpDlv+RbV!H@NOwp{ zgP2yKJ!qn+jAmY!^D`g;%16c-@vr;hgCvvvZy9VVQFB zBh}8Oj(GsPNCOzreE6UxKhGK8U@Qjr89??9iVoKMSbn#XPes4FdXwRWmshAHKX?(8 zsj_mGJmZIP6Fl*t?#asb6Xydt;^U}J8ab4ab+g6zQ`PUA?zB2g-0rPbU0(! zdGezP^bh6JE)cvC!R|N#PPbWa9ix|cDSG6W-4+I=1xrR zMltGA8TO?9&bXNT^+};pXXg_wg;QW(LLMT~rm@ImWN@jp)sSb+X_cN)mCtn@_Y8A4 zcHed=Pjdocnb@~p_)$i{_1u1JLn-L{iQcF1Gxzf)96R^S(TmpTcM3@-uiQ6uu@oHb zVr}!CPFH#Jd7D-oa)$~x)P~m0S8BoFj?umia`S76JPQTfy%m|D+vR;{Uy6Rt&V~$( z@oXKjFz7zCZ^I13Iw8)v6na=e+uGV@b>n4MX;Y5bJHd2 zHZ3z@N2;EDvU3H8;5mJpkPVygD}oYauSf!G?D7Q&DzHf z8s+e7el%k4#=)#ug&+9!=MIS=xtgmhNx+T8^^%wm8@6VR8aG2}7Q;2^{Rc=v>DHy36=kH3Z$>JivS2F$U{ih z+p$N7Qd~7xVrl1^lH6?E0<0-)|L{8RX%gYb3JuoP7%E%KauiL37bn(uLfnRsY^1ymjZ@O$7_k_!XoA+uKTomcdeO^AI zc0WHgenI^8X?Jx16TN2w^;W4sJ*M^GqxBpJ>GKMja(e+g})G zKhesz!w4!L=oFrt&EJk;| z7S4AC*8L$1+s@tQm$zjMUd#D$9ZV^Wd}yA>@%V9j_9le-Du_KF59TlDQhp>Sy0PTB zUR7Q=J8G^N)zbZG%=EC2518b&^d=QV!a9gnptW7X8{ryu%Z?u(#-m@1cS|oIN!ZcR z(+W`$0iv;`7GY)u<3xIvCVKVX!|0_v(5}TB$#3Z9Iwiaat8jujO_(wPas0cCg(4b= zR1Zvhk)|WScq4HH!_v}5W|;b_=qtt0l^cWHC6Er9JEqv0vVknZDk><7dB^{!!|~o4 zQ?8~XI!hqA;3L&WO!I~po%}i(ID4Uztw6g7-NIlYLn;hvgB#jS* zadTOW8B{NfD%k$VWuC`ih??kq!2DeH$ui#W70Gde+2n`nw7XEf1GqUOyWfj^b?%Ox zWu8j809SwKHIlS6*Ot#)HYaPD9jjYQh%iiggl?`;>_JL8H)u6&j&B8AZ`_4t=N}t! zm-2WFv;h$U(DiCuj?e%$rJi&92AkRLec*(39?{}{Fc~QD+MAd`riB^HL*9UAlKXj2 zy5P)*Lf{O^WKZBL;f}dFMh4QaMI=DZ%z{h)$hzjJqBKxJS=}<-lm>ocybqrN@ z1#CtGBhl0_R}riwgFV-m8xcCH^PdGkA&_s~hr&Jl{4B|q4r(U?>V$@X@1E6IK?1D< zQe)`okV9H33zgEimvTN0Y?ge9=y-Q*ymfLDNlUZYXCEB~m9`k6 z2Rb0HnPTmp;n06(%cz%ZpG&Md@7et#6NIG0Kdd5fNXU)H^95ghdT6HJBs`e&88NGF zuJ>6;U-XS~_KLaD=gvrZqPAuoB#*z)$c~8HD7@h>7V2tW^BAx6HcZp{9Y|?73bIaf z?K62-#MzO2Z@RFDgh#X^$wqEQn7THq|E|Z#F$S;jO#D< z#f=2OFNA!z@Txj*j7zk_#ptC(qCm25-~Pz#8t)PL5@(gCw-M`q*IYGsH;%Rbz;WEo zyv8=(YVm@iF(B!o-?;9o!Pjngl?OB4Ez6wd2FTQV>)6s{p76kixd!XtXymf;yhr=Z z#VS)#(T@>O%Es0T3M$a$i{0)IvAXTL2sn{3(o+P9nw@5hB=5Nbn1 z`l80Y6-L)bi{Xz5Z!rVjoPurWh%26}71M(PhYg|6fq^pYuNqw2kA?>wj#lzv>Tdji zi7{4%ubo+Xh$)KX`h~}LTaZjxohUF@r%7cbDF*d8yq)Yqr%P{5kJ5Rw{-AngA-tvt z4XY@;JxEol&EI;TYgQdj ze^lplrF6$v|ETxml2ZFc!3QHx-x9aOoSmktn#41@T=Ux_Qk1zOz7|lwk!jW58=lSg zxSQlJulSo{FXAtU{Xf(ZLs}{9F989?qbluGpy(eZFEvxe@gUgp8enOReW!v@+bZ~9 znyReQ|HUZTcjg}J;e}9wUwy+6HR$~O{4&TOxEh0F>r-UoLr~{u2)IQ|EF$v-cKahdw3{GeK;q_ww)MD%2FLv>@Wac$c|`sH!a?a| z@pndLw(k{>-E05NLD|h(L`m?;WA*X>a8TF>t~O(bBuv~p@c#G8?ce`PbmRX;K{0sP zc;zyf{ts^-XefOC{24G$0IL^}3FIinOI%gPP#R{9ZSWAh@gH74p!*p#|3>kNooM!; z&F;q&@S6p~-_@5<0sefVNFy3C_AN3pOE%HP#pL1P;XCH6&l-RKHgv&6Nj((MbVkG} zg@kn8ym>=IO5*G(cZI{Y_vU+tYMm%2UEE%mW~Ken=H7) zs4BNT-@%xYlH#FFJX8DYD;+kdGcDdGkCfeh)x%saDwfk6bs4C^i{2aH{fvuFD@=3 z^<12GJx`CDbW`V^V1ML^x)A5#zQptc6Dp!W@Z%GptbapTyAu+DK}Ye#`A%G28$Q&rN}Rh7%P{#js~1fjR|tHf@Lv*+(nlJ+~*MB^(xKcVoU9gEe3 z4Y%G12_x)4+9;-5w{E3++(L3n2l;*rsAy?vDY$Ws6fb-r1r0$3_j!+*Y<4d5binQ` zXw)(Xg)q{*VrIDgE|0}Qp(_b6CIBxIw1~gk{RWo#f}@8lYJM{cssOv95Qu`O_&}T7 zf(h90X^XT+wnfi?F`P8=JTzT!+pz%-yl3JeHwsdnZ^Vxqa^*9TgST?Y}#NOYegE{?`d& zK(9UCdxz4BJ*R}AQH9GQ69!KsPfEzNfE!RxMu8dWu}Xt{m)Jw_{9oaXzP`S}0L2Nu zMa}POFn06ug9dg>7WwRc8FnN)5=dk45K(mwHPzc)MukBdQWlT^`15 zg$kY2!}by6p$DYUxGNGUh4u8_fBN((kSFWQ_YOmai5)C|4f)ch#s9_FwK&dwr-{PR z!H&1}5CO?>@BKofj?g#1zetZ)IRdeh1zlXi{~w>;YxcjHy9Rw50r1P>*FT0Z{sx8& zr8wva0Ja3k)&RE-s89+pVwA3-2-jWga1m@^E$-eml+g#rEY8hh>>f(TOoLJhjcU~& z0+{PytA{9X7cT3I{j=4TH!zebk@bNV?3BU3JKn}-rl$+OyJxJgWG0++l*#&u8<+`v zLgm07=KuM87ndsJ#TReLdUX|zs|lx%z>z?;LFwxUyu~1bnZea0=9K zV|$8V|5s=>cxv-kXtsOzkf_QMeh?bWqdD$ooRT!IBJc1rk0yYaGk7JRF=9SiWbM7f zFKRG!JJ_*`#QGtVeiKgD=5xZwF1m?io1sM9$rpXf>8%JN@_H1)T92IT$eSeePFXn= z$U1@k?Hw^^5Z|uxZ~E(OPboWA926#&?Alj2tULxhvWW5E4=XGEN7CxmMhQDwJM*34 zvMkjNBL}5Zc%F+B`B5*bH^|-VO;E@;c+mgcga7G20w)oup(VKyP`GS{?7A5x+rIZe zBa{ZDl2%;9yeK4%P~(yQ&V24|VRm)<)2coqLU?%shf7&vAw@F@U>1d9tq3nWHh@H5 zrjHI+(6WXf=p%gjak*oNcSXL6QUsv1s}PH^iz*S%P`J^<&h{(&t-D{~k?|RHzI~Ps zpB*``rhWWaF`GS+=bfkyIhV$KhkM_Wtb)tH7s<~y`{;K1$Nn@#U`Wiu)|b20azj;HTAZ%fx+{ZBw?7VRE2r<{5rzfAZl*{Nqr5a zmPj+{k?pHeBy(Tv)}4#?{`e5&+a z)sFt*o8E@!Hi+W%-YR!As@}AeODh!Th91&knQgNSeI43GCgZy~*Tl-YPFfeE<}wPn z<9FzBJw<%O=oNvkcBr_7g!<0%Ed$R(dffm_`Y{K0ZF-Uhe^Y`qgO=MwiDnZux@ksh zJ_+yq?samr{IXiqj~MxZP8-RhZD8sCu>M&Ub*yV$b$`y*2dK$}40F{cnnR(n^AUYg zYuQ%VT%2`@uM%KSDgC&# zg=$1jq>u}`INVYGz3>*!6yC>ff}{XjKJMsFNlFaS#TipcY$QYCery9JvWzW*8T^J^ z5J*XqeO#T`>+3w5r(9#Ij{TcfXL>(&t*9M8eoH?-Vaoau7BWXA4RTUedm zTJ6Bwv|oZoC3MKIFFr)i*ZO1XYl6^3KwMiy#I1VW?Ks3#Uze(E6ulF8`H_vm;;_5^ zO7On@wbF@}ukxBPT)5$&!kwP=@yQrg)sa)dok!50l`Vy9ow2W@(0XdIaf7>|G#fR7 z&wz%~8gJt`6{Idw?^3=0k>`^Zn9T7VwuS?bfV%)ZdKx~ySP|bGw=4UH<@wcAV!Gs} z_7r8XFT1W8K8T1Zr`0lPHdo0|qJu;I010;5VLyIIot5(sEBP#?se1%GKb-b7VlIy1 z3U5X0eO9C`7VP(x0NIP(q`rPIdYgNKMq?RJ=j8!wyQ#$h2(|2}4*F;&%(w;(1o|uw zu@12SMyAVIM=6_4KhMH3r`Z@wwX>Z=po6tZOb}M~5cg2U@iL>~a`?{-xFz@EZ{xW@ z{znz~wk6lWxUAvJ9J+_aqe+t5BY2T@WJZe4L(8q?EDI+=ax0LKFwJ}T?^PWcOC8q2BD zg@X$4hU;Hvk5^=3Tyvd)$b(VA%tC?@OmTxA^mS%;zCyezHp_*sZ-<-q<=|)}KH%XQ z26Pxv=<={6Aio7K6<&Zj-gu_nKVoc8rzNb1wG;QAQ80xiDjslKYQKTE)#H+Lz)t{$ z)NIg9uVmvJG!Dnf^ux&hnHZ&KKK99_29NC8*iMs^yZUwS!_rTbyKYER2ZkjAr8?V5 z(2P(T=VjPEIYr0*iJZ-*L61TAJVTD68u-TEGHF?MokCU0jqEFnB8cVCgzs=BStUn0?|s)PyYLh z4xO!0*IP0>r^1u4YC~WMV!aRUwG#w<+tPO0U1g+TIcwm6u?kDyAY`7!c^8G{xRA@M zoLnoRkW~GY(v#_OwaoiPl3O|!zr^CJ$CKsWCoV7zFS)Dan2u8tI{nGLx%aF{k?b(|*qMUHj% zl2jbFVZP?e5vFjj(sJ5eHnvZqIP@QLJxDNulVOMGv;>uf=+iPd=J7U?Nxde{5k|VT z7vJAKl5OmmYi<1&BDTt0==OI&F|v-l=FQLHK=%?uG>tmtDl!E7zwzMz^KS(|MN~gh z705z7Z7@N{1{l~11fSzXe1X)h^q>B@f@5pL?eL{kil5Bqt&Q>1?J%PuZ*-p4Rv=yEua@B)lxi(sY6)<2iH9hGj+Q&7| zd@|glAIj*!%%Jrxc##*%OX2~6m$Bvl)H&&z+AAhhWJBjDAZN=k>U=VW}I(j6hnjuvY!51L!Vnhm}eNnE#kWM(qDi$TQg_QiAqp6Mg7 zS(~MI{ov=4Wm15MFX*~&+a>xu&*pHNRDE(KKUIc==X^c`5r_80H+(FvtYW<)ufkq! zXq^9%s<_1OyysewpI@oJP+z@9!pV*M_V<_SsNw^=fwLEn{caQ}r+Lv#I4VX1os{aO z>n*eH`>YPFF){2ghSi;Thw;KDs|;K$I)T~jm)~cPpX;ykk=4zF_&lQFhNN1r_yhm^cxcW*6bfOd+B!nXu9{wy!=vriG-YrHS9TaRbbwh)ZFOb$%uv{k}9j zqU&eeh2wW7!(Qzf8bLw9rS{S%4c&0B{CJy5V!0R~0}+KeAXjV_6wlrpv_wYJI}9WDH}FFCS%oj(u{jI%1l+h8VyQExRLk8GIl@f45uD zmqEqo%eh(4qz`+C(tR>oY*F~EkBDzP5<_- z`P_a`c!KGbS=@M~nnGM+9Z(FiQ1u4tvBNW~1#N+B$BpK1*aUcRUsXF5kG-AA-Cnh2 z;q#mQg(Z{bupvL@n6L@H0MM{{}(P5aPVe<%K`Ho7aTqx5;nODM)h^Ibg zJhkvyQFo`VOHa8??`QO}3ci$jGk>nD*g=BlY1(dKraLt!tEQQnfH63zxzYMN3a9jh zZ*~$Llv`O!`&!QX)j%h(f!X8B(qxa$hsnPnWDHm8Sa*TvP4vSH07?U~w?2wsFD!G- z9DuRzh3e$-@^;aF9`qFSaEl$|rN}r&*m;Gh(9uw)vIZBtBQ)7A|32%BK!Ir`WA+1X zA&97&iIES&9xlNqR|0JFg%o+xK{(GZ!cU464~_AOR;}_0bWay9X8Zd(-$kvJZs-*3 zbn;8l#M9rrclxl9BAPMD?KnnzBHx;VfhCR(OnI}fN%w$!wJMXC7u+gB43)v3wdpz_ zMl7GDUdJ8d*_`}}*m0cC^68LQ=YN3>f}e(0msgOA@;*?YQE_aEnVM#i5kH`(e^$g2 z>knZnQ-pr=gW>y;O{dl%w4FP!c@LA%2voN)MR6!pAC?BnCnn5TS6;ldBC@TD^V3+y|;e#w%j6w zg0J5v(mbz13(SGN!Y@zhX*hYg%zSqSnj6S8DFJ};S)At1jgVWZoa@mWH77ccj07Lr z%9VH-%=y;ihY$n`OLD<2`V3ya@os#-7LhquJTwu0ola>o&Kl-7BI#4fqrXWBqyPfd z*ApC1)(#9tcfauu`WGsEx}zX4^@{hr>}$I7fmP?5laqm=ow->L^th*JTmm zOwiKYY+|Ce?qu1dD9jYPyll4Aqc3)nR2h2xl28Td%9)u!`2@TALuWUD8yEFTZ3{$v z@do8$FBLSzrko_WDh$XZlGxy&2@6l)1%yOKN=o_$+5joVp67WOYyTQ2{c+G0-XC<) z{%8b%aT=*&`iqM<8N9r_=tNQ*b$)|#q=G9aO!G&73CtlsUcrGJLljyeEBWa%qSqA< zg}=V)3Ll3g4{7Asm==%#?Im+u8K!oe`WNt z61BFrT2P7`8D(Ig0eJ4z*3X9SUy}*$ZdSwpXaW4~898)nS&&AMniLP7!rF}8bGV`? zkIDzQ&`w5)V1rZo(vWkbf^8lm>a$zZp9^mM?bS2b+lIam52dwnX=p36-B0 zMg1|$55WAVEC5!duwr|fByZNEx}s$q$h0mReDv(c0EVONs~l=u>dPp*}q* z6_7`t*W!CXTGNTBK#|F(QA%EZPf^mB(_H)>vko06Cuc9%fBtb|Qk1GXo%G2b5D$?r zy9k=n9nSH-X)tp1vpDtnO)zJ=->;}7TZ3!-Aza)s?Y%;rG%Cj$@)jdI+st693kK%k ziEu5=wqPP}nWQf;7Z zdjU=cj)TyemhEjD2NQo0%E_b@)?MYt+BF)H%$iIodKJ)($dRKwJf_RIQ-3yt3?uTf zHWQ=TOPSI!xuwXy@{=Ju6MrC&aUJuM(Kq}g&`P1I+9Dcu7i^gK6zk~JuSp0Bha^F< zmgwGt;81Eoc`jdn|Nc&g+bbGcDk=|vkK%$*3kqt35o@Orw?w;aw^$erf49mMh(br< z;oc||hKkZZgyB*%hBFItVHeM(j2cb=`*ZuVl!8K_iJrL3>(?nqxj(U39z8OPk}R5g zI+&9c`dd~NFmngEynJ+cZd?}B|G7WD@{fN&N6f-_sVD_2eE96Ruos*nqoQPWbQ0Y` zqp^6@MTKPKV@*S9K~FvGh1MMu_OUzt8WegB_hWa#)6(Qw1LMQGuQ@sG6GT+;-;1C} zX6i=geR{r1PY^n_{rz{0IbkR)GdA?PM|L)GoRZ#LwhW*%gp9@GEJcPb#o4kjFob|z zZ0YRWU+BI+&X^uU6`B7^->0Q}ju;XW6Z2@vG)q*;Q|*f>3ddUby2+;4+~_0q>IxZ- zE26SyW+FE7_po6GAG>X{Sx0UGTR=mKC;Q|+$3pZYq*XR5myXkudHy`)Y_Bhg(>&Ya zNkjI4d3r^~zQ7sOEgq$U>E3k=xqH5PPvmV1*uY5E;+pIPn}ok(?o?R}Q69Cdf?o0R zXgzFP|5ueI8rgD6o&;B>`= zm0jz;55^EGzkE4&;SWhT!%ROzWj82;wM0ODm-^OqFHvpA2jVujQJd5zVtnVn!#6hF zw6I&L>^f4TmnyaWd8=ZyKY`X{;N`IqGCEU0%B@08{7+9^_&FpsG>D0)`1bCmZ=v#q z(AQUSJ);GkOTb*k&mcGp4Fzx%VGRY39SX+?gRlAnUcfCpA6jniC=p);cTQduw(2TI z#Sg$%jOH|t++7(`EGQ_z_FSwxK+8ml(7=L`(e*GAd@9%yFx&S&aXq10L>MXymF#yz zE>_^>_I6!pOpGa;C@m(Iw3cr7-P+0qI3F0IZ*@_LV?Ky1Ag@l3$!E_8w?Lu>R(qk!zv%MWP{q}4RibB(*jah`A+YCy>uYQ zUz|auWDo+$$hOh2kaCIX&qk-PDr0*}J^U?-${~R)-a#tyvBVpLDzY>=Z!>FgdU zlzuDq5E2jx4%kmIphg)I?CXWf&8O^E$4I43zpcZ~AxSw|pTer+vSb*;W>-;74kA~& z3C^cz9wK!sGr8aIW{kV%r=_QlRuB^6Md(I8mM+uI58#fJ=Vl5PJ~Ndaan2W9yZ>PP zi}2~@Cmf1*>6Iq^c0*E6pVshqU5dE_%;w%$xdYsal4V}Sg% z>CmE4X)G8SvY_%e`{|WHe3Wiz7@DL@xwN#j4-2oW6D_Q2v{C~Z#>9TY8*NPtQ5<3p zrOx{<*@71UNoxgS2!`8;gBAent;TA-|5a}D+jms%4gmHZUkdE~Ndq##XWRx6FP-Dl z5?+M>2=*;@f63_-R&RWgM_z=w_ibOR=4#MlkwT+E!e_TJ5&(*i(p56L;;?-iZLpYT*mY0=-M@|2jX^ioF0&l4(y*UNBK6% zM8x{%+!Mn$hmgB?(lNBk0rI&yoq0+WzEoQ)xzXUmLng+sw>;Fp^pup*K~_x+Xg_1` znp%H8J18yfYJJIQcs?}I3?^M5D6zGlzu)p=a~W3B1i5@$Ed?rKF~+mZ_gpCxf;}a*i9%%iK?Hsy9AGwKwUl?*#Pq@3XJN>+Uzbp1PEL+zHoKqf z?3WO=%9VNdy>eg|Mvg2?;nMe*jz<(O4B?grCu^mJeM#ph?2c!9?iKLx$oAms{jvIl zq3dW=Z+N0n$|>cM-OZ-zF+{`LEg1td^`-N%( z&|sP%7bn!Gy?a)wThTWz;yYFEEi?6-aMX^NG-V~eU@p=)~Mn=@v zvyaiJihA3pZCFD?wEkqt% z`|_3cHlB~f$%HGIm~oF!ys`FaCOwYJrUseYVTv-e$GtQ7|-))qHAQ z^E1vQ`IC{?u-+$Jn&*_Bg%jei3HKAj)ZdR$pk0A5+X(}t{o6N|;HCKnhQ_j>W-H7t z%7aOq_QcicXVqC}@g*bvB;w2b zu7y_`6}NoK2w`G~*sMrlMZ4!UB61+5rQU&Kvfp=3m~r788$9(?@8(bCcy?2mJCP5jO?SsDQ4+1rdNll^Abkkduj;2WoL)97QZZTDkc(q z{W4upxC0Urmq5ikFDx7p+N<2sb~FE`C*%TC^bdp@bHOp3rVz|WI5@neTHT-S?5eG19%Z+r0 zFMeVVP^r|IFnZi&WHekV7_dJef!;i(V;6t-?#1@a8^DTzD+1hnj=Bo1UsTQ=GQ3Ze zz9miq!zd)L0C0Nyk*c>Bt@o?56dRi||BPvwWgaULrA%8Z4QZg%ll$TQBDL-w5I=Wy z2B#?~kN-O2G_1A0`U^^arW?(JR#pxEnhgr|A}8_G_>md-GwToXV=0L}@fW0A_nR@T zqCyhj>zbf;#plhJixMdF3H!y%f#$j-_XrW0FT1ND16hTjTIg$1)Bw<^urQ{VFJGRw zV*dnqDu3ej5lX)1J~4I_ZX#dW2LN$vT4g}nmd3s^fne5GN?eo*SY5Mh7#h{R7z@aE z)%*zD3M|^_m_aIQI%2QCq4|G1gSE%^x@-1yBXdH7moz7u4ZId}B-lm6BO_u`SgGk0 zC{=pdd(ZA-Z`CWd8Ct&NtbYR?X)+fbAZA@59n}Fs4|!s1JJNLbSP7kpQ3yZFVh1uclT~+6d@R;_Eeg+QsFPw$m;Vi zU%qH;n5?{3#1PHFg5rI?e1*Fit|7}@g;%7Kbk&ZR`wP~&c; zR*4?(uQ95Ri~y}UQAuCbGVbAPsQiHh1!O7eiw-HMAO6a?ed8J}L<%r}`VgNv?xPS| zc&I`)!TU-}XCcFOqbE|xN3)>#Xk}#G_3zJ)xEtEv&jCidwpNCq1h;jIUWH+Zf*R_z zYqvpy`={*4RK+q(ippCnFo4Rf?>CTX{VBt8asmW6vx)?@HD|g5KDpt4;we>{^dCQd zG~VG?dGVrOG-I#w$l+$>DCX{ZM4=l=T@NZ2a&hucCH;SckN1hcewwi7Kt(FwqvX~m z;PbSGhsUO{*4?^pXbAMF?|3(w#KFC)QA+)O{yBtzt_V)yGiu}<1yIj)ZR_DfC2|=3 zbBMC_L728pd*_CF4ifbtpnR@x46ehfwei^w;$wQrQnm9ObWkN3@o(nlKlcS#hrg=( z|BXzJ&aF?Of?{AppCGH!FVxgzO##N{Rc~bCPYUed4N#e06+*E>?1!vO-vPaDvtB!L zlD?0n<>kS}&|W9UL&2YZ5WylqUJMQm>M1E;)}K;}V^y}8C^X%9RrWT-qHGE?G%|9K zm1MC`b!xruW}7J$sAfL`PO>F5y%!{{WI2W$SpRsEJxT~S0eB^y2N$v$3DGMLg=#0y3Yz-QH(oeGu6lLuQKKFnV*d=A z{}{(Oy^Z}`S%VG`V?u$|5cvSOi7sNM#w~7Gq^70()0<)jvv;F79VxW!J{^poD0RZ# zeiJV8S<})JULvE7{W<9;#Shi2vFL{RV*7AFyQT(R{hXW2Nk4*Yayli;je!G5jlnd#L@F*#tn%9jPbZJRk<1CflxX&_X&eFksW$ zVl4IYWrRiL+MqQ5DT!u&3;oYTu4t}m@%3u!Si$3*Z6Z2OX^UrBZdcvLuN8aTRtr3> zBy}79wUU(%BisLYlO+tWL2H?#x$Htux9~MjOG2}_2x_Zek9sF&dLIOrHAd;WGO2;J z1%nq|Ny=;Sn)Lx{thSTrX*AW5$KURveM4}RBrG`01d1^HUPNjMth z`eu8Dg4v`^#J5pP%vz);(Rr1w)IY03bXv?z;rc%xcTc2s{Far)O7yLbMi?g2+t;_| z{-;Lk7$CR=Kp9W^3H5t!rFvPGW*a)ZmV>i{fJ}D97q+Gzhx@vTtR(C+K_i`owf+k2 zSQ$EV)#CJPFqm>< z|F>>g{)X+6TvJo^)c1kzo&HVoH|C2lbo@@&7meep2NNFNA4ztd)~c;7xd=PPl8Hz) zGzI}>9nbb1lI7aRv#|Qh=Ge4YjGC4|zvPLO{bOM!YveNMh~XX|ZTTb_VC`(Yb8?DJ zde2Mv&lZ>X4${ge8oVoN*kySJ(0O?K0Dz-$b&iKYmurI)hrLxtEN8)xkk9Bc7I|5| zmit;WU)((%oARooL4Ij;+GUGcG>nRGBKnD$8QmuI=bS_1G%VGpv6Umig$iN3_yRN+ zClf6DF*z&`8hj|+s2AeZOu!_$1|{BY-%(=(LYl8$D)AL)77Gsk8mKOrC!95`d;DqH>4WEivApKsC;LhS5fy}f2IBkdB47?+(jhXR}5 zkCqUXQM+sKCV#KnKlX@^3!zJFN84@rG=dMbZ*1>$bc7Cc)8Xb_EPhp-U9~mmmtmoB z%i0yr-d}lVTn`w?Beol2tE*Q}HXeMlMTY=EbIhx2f>>6*pRiAGcR zbKy*vi!=9*@>4zdM5(nka6opd11I0fmUm!BgX3Rea1NMGSIOInZ_n`AnUxw`C6_I8 z)Uyt{K3)@UR=i0#vS2ZjNHVg}?AUnQ5@r+OSo1x*gH@T9oxM-B$NXZ$-JR~2Qn!%e zFTFJzV`srYr}NGFpx(?by54-<3BD2K_=-;J)P)va`_ny}l6P(i2Y#K#(Z*VR=u8|7 z?+q>pEF*NPxgtsOU^2T1XnzlV3t(AVJb|S0XfTJ-O<0$*FvU>E-J69k9SRG_x}NRM zC>AsdsKuRGsf_4-THks(c4XiIK|;vm#TP%}%lyedH#n=KU?=C!&O(ljWr`H8^o>U8 zJ)g`4s}DHiYA1XKYJ3#<_Y8=jGPyxUI8wWA);G}!^$`uBw6bfisa?tr`a?}sV$1Au z`*_gADJi#CPB9M8UF^xv4v+8($0|kl9@16aVq!RBdf>Sv26%!58*_(1XkNZ`m&Cf_<@o!VwP-<8`sulP=7@>2 zyjtz^ZN~hT&9?k^3k332=gaK9!%h`vV1ft}I#zU8Mh*>~#?Kd0!HArfhDwixB z#1n?c{>mg((+K9iGGY>y}_^L_6uUp})R`|x$H|0z8k&Xtjk4-eKH*8#g9^rfmbe|uiqymH~fKF>p_ z^R^`ZecjK&m6puJi0cF!fxLm3V>kjw?|Jn%8CcEqv5oVW;_&5DJFeKmDo zj$CNxtnSs)WHL^CmtBpO02sv-ATScQv9(=0Zp0MTVuO0RVwu7BhPSR_=GW|d%f;}i z2%YV+SL!YVVQQ}yFRag#lPYJj^8lVbx=$mad}x=@N!`d8X5VVXih|AWIkB+Bd_3p3 za7%(&#DUP;Qh>WpSP~MwE?G1Es1=_&^fkvNkX>^@ZQ|366@|93qvm}cte%5kf(Hr# zEyGheef#mwokRt{@5S-^jZGXnOb+e9Si835NN}cKjM}sbHy5h~J<&Jvl9-qy=s4o< zsxIxsrQ?zR1g)ZVyCA0N?{}~O<-3~G)_52ZS4-T_22-CJv0cY~OahKMVzVo~JxzE; zm3eJ?(|~PY$dWb3VyNX90=7R|3|Uvw9mJ6hNg)QMz2s-tFpv8_z2aH_eO)$-LyY;qE{J% zsl0f$%0!Hvx|W-NI)x95(rok(m6y}=RH^cS&?iCTaqD{Q=^ib+HkGlmCQNB4qRZ!1 zp3jTNm9=r)7n|@S#!gN*sWV{6e_yLjAsq4$lA4RNJ4_s%@$^mXHEQ*qgXI@HIQ$Ef z{W~@2#bNG^?aIb4+w*HK=qBuZv|L&?qbaXj)7tgAcX5rRMO6-0Ud-3%licv^p7j4^ z9Iv))`_@CL`piqXya7OlJ|6q^N=c&nQu^~XY;oCwgy~Z3EZZt^oezK;ZYux#Z+thgi z5!WPhUrK(xvPq8xIsv_ZabK*PX4Hz>w!%Johv<{-FEIF?)6?DWuPiUT4=SseL&f%^2oBHW@~Da zd*s2yMKdm4_a1&1QxK7is7lky(71x*`pC1jP4Z4K_S(3U+?jUc;Q(K!+cY}u`Ps-q z2EnRJ?i)Y*66@lD$X@+=+_g=z@qF_c{*vkhXy?B3`p>x4>LK#mEnQ*w!lw=P;d~yC zM{n63r18J$9p^3;)A{P3SF=yY9V}8POls47wE(mRji&I9yX=tlzmI0 zpe0FZolEyUKN*}o13|VU;k<(|pFJkADp|;A8sMUETJ#uHg`I*b^3dFpapKU+61fW7 z_;NZpPa&7Nw_8u1#D>I~vU4U`Y1AEd&pNm@j2>Tjy9`eCoh)PY-7=E`D6Fpj5W^4s zgg4fO7q(UB$3oxEk$f^TZjjks8$+MuGKgE%<0^2ms&B`45GJU|H}>npjAF6RU^|Px zq^@yhwR_bDi|YXp0Ci1g^?+O)55eZzsfwRcxx-f9n9r~7^trn;8^<5PcfNbvbBDXC z5xnhJ8FxA%b54kNNFTpACgu4J1l=E#xEzbvGF`m!_FAM%a@n?ydA}gIE|{jfZEg%x z*(DcT^_>~pBd#iFW9FCQVd=uVmKq}yZ$YNRa%Se<)8!}8wNe77A4ZV9JEXEHYH>=X z9Woew`w_m1wv(BQ1I6|#^v?}Tf5slL2;)57Xt+3AkOe-s3ciOBoU7s2|5!df;X%Ba ze3i?6bUVl>I{spG^=W5Kf^E-A@tf z2x6&4TuC!`3*6Ebb>Om1+niW~0BAC4Ps@=eFZr`*0wF~&wMLC1|qwJ!mIH6|?-ssS4 zYCPY}$m}w1SN&E-T%MDlGS5mAc$G`rl$hA0*K;$dD zUs*iraJC2}@kBb2{8AkUCMVr7=Pu9aDfA+-vjUjz5~f&#E(w^yfyp*zS%bMz{v5wj zc%dtRJ0PNo+`YH65#N+;v8d1zE5p8K+_(lBNZ~dE#?OV^dXQfTZ=|R!Unl1jQNv?1J7;kEX(u4>lIs(UBVYZ@mz;m4k2z{ z`Bym1w?^g9qfl-i9iKD9i6wGL}q|L8kzip!NuGIcGf zmVjqoB_+mA@0#dS>FY>+qhzy0}i8O=#l^E7Ay-{u|cvD@BUCIXL>EU%u(83DhQ1?PORtEJ<* zm$bbz{kvd8$a#QB=V|GI5vK3Ow(gK~p-_XdUH2Ytgl#8d(Fj@5S4E%vw_i%b6wt3` z$R`-U+8qY@VaEeIwJK&Xnn3)FP5TB;LlYcpAE=9QxvkdOo_&!c|8MYuv9{VQM0}zk zNwRbynLb&y?% zPEQilxw1(^{PvbEo}kMITrOYk{dHLR#xO{{W2p=`T+Ju&iN#;4@^u)5N&8vHb}Ucf zRNJJtm5w;$Wc+K)4(duy zZnVh0mJp?8K!At^Vq&g@f<1iJ3%+jG^Ag5Be>wQRv*q9)qHRCklRLk5Xwm^D?(TXR zL8Vl!$TVm1nw}UB$~nCEH<9)NTy&wz82d79=r7&^V4LKJmm)1D_Lv;_Y>Now`F-{p zcOpk@=fAL%K27z%GhVUP7dtSyYI{?Hf3_HeIhKPr6ZY+UX;(1%ois2>xtlRRFCGb> zFUF60&0E{@%~lU_*UWSywkob$4`OZ{?gB>Lyq20Z$#fS(4X(no0(-8`812=(efwCo zaQQGPnpMDW;;=iV@*y)fp7}qFeRWt=>)N*h!l)pKK}i`PB@NODNJ$FPDcwB-4Bbe# zbeEKL451?3-5moAF!TUJe2cx$8|S>=K4){yA9!&&YprLkbw79f0+TLbC-{6FCSMa7JsyCHbIm4~#x?Lg)I`O5D8t8XeMi4Szyjm*md zR|}`^mw$8tjvFU3n?nh#j1~nv+%h6(I-MTP!`H%RY~r;cb6urC0JEt-bDeS+m|NlI zoKoD4<-zZ*?pX;Gw5R7A5Whh8{*hA0+!1j*8lpX!E43Q5Bv94n={1wi_sQE9&WqiKx?h=u1~4(^25#%jlL@jV^)_om9=<(4SsXf{*yx+G+e<3Om4({ z5)-4-qU5N=lx)mwOtL&&zNL}{f2sAInPJU!YDyg~Apt4sLXYa^7jbR!C$rLtdhQV6 zIt2y}HfU7EK!DsW#{FbU>FP9affr;k!L?gf8^h9EIWy&3`{FPzA+7k)>rC!l9GW}L z9z0h+aVTf@7d+J~e#-{#ZcBIqSNS`lX?IRMUm|G<#1YpV?-C(EMP{kM7wTW@TV75= zJvt)At-EkMW?-gqH8Sv4p4NaD4ZO{L^`%0|T+eo;T*}BTyS~Jz=u9B?ZuP6efye7~ zNjt^;lZr}r8g#;#@h!kQUz@fNe_OO&X6){KSOQrUaM-yz-fUS*xMqqn%B!4*%9Id$ z+HmyDJu)1Ogvz{_=u5F(-rQy18@@09^5R^p$Xq;l4)ykj^^*m=O@Mxk?U%J*TRd}U zBLo}`Xo^rJxjb)n=JQ&?1d$%{y9EB+e-N=hd&t}sr#gl$6iVWrYI+hAAPoQr=k*`G zsXyiCS@N6CAf79$^%YPDho6Td@%##qXI2|JXIqG~8(*+4K4dd90D#YKLd7#*kC8WY znu$7KQcrjPfHrY}#C+dH$9+-1j@*AAv%U2v{XOU8>Ij>D)*_&0$`w(vwfzg4+Bo&H z@yUJW`dPt_<2xdwkT6HxuKDsVU`rQG-Z%+!32eg&bMYlfA_WaiUj+xW4IU0J8xnj$ zS@n1(TSWBg{&lxp?4~4}D1S@JnayEoE|dgd0- z!G(0YGk|p9gCxhSmq%QQ?)M^#i_?>a0bNgRYVL@7?KJn@Hp9Rm^)yC;&%>!JhOnKQ z;6g;|O;S!HZCazfx9Nw1R8ZbK&o!3jU+n$uQ;^b zPj=S97aGD%uw1R0Cihi4vspOErsYycT*s+tLts$B3=kdxB>z?9-WHBGWiCdE?b!Jc zyB<%gQMi6*RD1$SxysKY#qGfNH!QQ_sG;=Nb z*WsGqN<{g{4hd*z7GhZ;3__mG#F+g~KNa?A*J?E+p>FIbLtc#-SO33*ClkpBPFQ;ZadZ7v&^fhuKTI}{Rf6E_!les^*bkb z!N;-a-B_W^%?Q>{P2?~lZRhY5w~tl|UP@hj9!+3-a+lxK(KZ358`f-GtLv+hV7Z#m zx@C>C&3u3GBb)rH+D8f_-z;2@4ckbpg(rk~knc9fnI=?Z$Geg&g&JnbX1`y8XS%f^ z^J!HL4>s-E)rlsL=QHlwP>DH|TDXY^+0{nKO$T&y#&HRRs!Z-O&m<*?=9SDu-=Jp3 zzf!Yf*Xhn#Q1uC-x2fG_O`L&5W~aKRKY9dv!dT2S3=rmIv)fq0w4AA(GG?eZu^*W? znO_VbO84Y9%kaWRZZ~&$pS<0F_sEJIG&Fda6EEq| zbA^))>IUezW?FfQdXnDr+nayE+;Zv%Amr;|&xG_Vl$H7Q;IyGFpTN^*P>8kxjRs)l zpdu(iBhxq|5G#1yvTy;ZP#g$*Nz12cZ|`8ZJ1enP-jQDAw7g&ywkbA&H`D!NrhZ<5 zB^IUClzK7`(bF{XGu`Fm0^sJ{FZ`M%Z;{_+Vz#6ayt%9sEb3HZ&@&57 zpmMbB&#k_;0-yB!{{Us!T5D3bZc(L3iM><)2kyY*uHWmjg2=|k@0$o*=`Z!gK*ZRe z-|h4!NKTe(1{z*80@!C8}=t|xMb5>Z{o$yTJA`g6081$X9-RNJJ~5nMXg1>W2eOlnfsv=p#R zGuk6jUCY|UNiu+NDjw&nL5(H8Y(U#ovi z8!X9|*#{^6@h;2&&0)PzNd=MN}SAr-CdK^?R1IOzTd^arb|xv zgBv>4#Xa!tZSwhym=oOpy75;t4!bT1lS-phPw}cu&CR54Za0F52W2jLt>ZkG46UNSznbsgHarIUZVfSp+O~>vBW`6yV*tcQd6o@S_#lGLS7@3qrPi8YaQZft#g~E|9Yt3krN%uL&70#QotpV*s z)2ORe3p@$C6UpyZ<5{!C0?C4zNm=YF@7_B{qVD$sTE~Ei6PZlu{7#&QyJ>3NA*uwRdyHc?q1OUis9a9JDruwQ?{ z9f`@#I3P2Gu=gP;H9x{B2Q){_yxTp%}`O~ zn(I?BkncZ)17?hb?&$#{)SL57$*^`ZP}DXlO%G^Ez(e!g!T`tutHxUT-Vpp7b{+8_ zNvqI17Z?97xdqh<8RNa!*vD)@*0F01#M~wV*yYYG)L?`VFRea~s=-zp zTsVtB5I94J^+3aAb8TXqwJEj#W;EKeHU4C}i)+L%b_3|mXbzmM>7A zi?!4ZfvNXwK>>QTpErGL$E|U7_~Gs#!~R5V{qBGODvSJ^a71Qm0();|WWt2J$y^r6 zEsjTC@uCj|g-h$t?fEW&*?P}D?YOZkP%bkgtnM6kpyTS^jNmdRmABGa0m;MQ;cC^- zGbgrOQ-WbK<2o{?V2r0J=fNI8^dH=2OEMDwkfl#_bS5~2rRxp=1#0B7sChipE5zg| zob&Johozs;NWS)ByLkb?ZPL&rb7mLVu4@Hz zsYzqTr)2$n(aPMSp~KlqY!*E5Y$y$=buZQ%Zyu73E9<&_6&JU8C0;Y%Bo4_w=vBkT zP)Ay1viL$?4B<6W>5r-!G^YzaMc5GnPt_5S*D(KeUgO;kx)Es^sC-Kr=i?*06FBHC z3~*(`>QCo+OCEwU(Ifqk9l!B|K%onr2SVFanlA!!BcV_ALf02UHJICgOjIQzMW~BS*@j z;rrnJ0dwU}jJ)8=uI_{xi@3(Ljc&=r1hwu$y#?*}H1vyz{>s2{<|KSxTOpu)5b6Tv z{%Zgc>(#UwGWJw%a=fl|8heMz@#8w;c*^tIT`cfh0ULP%rN?O$pPNsOC?*C6%MUuH zyM8wiyk}F_wLgep@}jCH!}ppW;!65 z7ur$*%~`3oRiuBzlN*b5S$retb5Hq~e@kn10Mj8Q9A zRaJX~1JWTsb9Y;woXbsY)AL&PsOt755b3(MVZ%)|kDAI_s~i#WMU^#G0HTSa>d)4F zJhSc_lXRumy6yrCX%Sas6>tjJjOUEUnNjd%?G7+TsYM(`a7T*6$sGRZ;NyE*nPdrr zwC91gr4#huH|+lfP~5I{ddge!1jGtdVyp3*$e;yx8F5VQDFp$W!1}yA&&^!bx$rh# zKJNR3cV4<30s_286;am0!dW|xi4QPs#}o4tg#*1b+h){D@23O$iQMk>wU6NbaEc=K z?e^@5BxVrRp$_J8|IMFPn*S*}u& zk0)XOuoImJD0t4~l0lI?sS{tWzT&77u}gQ zj;v&sZqQLR#X-q(>yX8S{i|} zRcqLBJFmB&MoY6r0pcc5A6xB|bx1x14c$B*Esy`Ys3(1KgWLu(x3dgROF~RPnSf0I zHO{fV3`G=cRZE}DA#GujE!Y!fzaBl=;U9TG%oO}_+rp$|JQ0|YaBKRGAA?sBZlX8I z9q+~OC<%(^O8HNdm*~y;P>z%uM(~-fkm8Cnju3)@0%YLU|a6s)wg6<*lMh8=Wkp_}`))!Zzwn zDB~i7sqDYhFih3+IgN6f2Yh~Ab{dHO)L1E}EhliC<2R90U0Oten9x=I+KX?*CF*r( z)I1V!URqL%$?8J&TLa*1f1jJv52Sc`)0Ug6z8niB9x{C|V;c^hPIEXR;R5NS1kBkL zHYQGLLrK=GXFfv6xpJ#4<6~p{!|f&*@y|K0BdPOYy2mh_W0{xcwWZ_5q_nAyDbE~^ z9^Sa3m=-yt zhXEGKzl>i=DKk&8(Y^@5z9(>`m#Ept7uq=`iakR`2Ql&qju1Q-%adg;Jlr;WirI(7 zx>`Ka`<-QzRkQhc9A>}&s&%JAaYEOu!T~Tno=+@9>Zlu5c+J}PkRNmxmGO=3lnEZf z(;@K}hheoc+8vXSMY%vaJ#%9x7 z(b(&6MZY*tKruHtH2q?_erdwP_aR-yQ~1;G2RC#6Q=GKeRch#*A0SoW(94}oe29?s-d73B9U_tI0Q{Fvb`y2{S z2e8VNkb)3k4l{G?JYR!|e0EbE0)QJH&dBG@Z^>cPBxS&Gi5~FstbxbI$J0-j9vv+N ze3z`Ua-;e^t~v3bFOwXgQ68qc-#Y(F%~nxaNoX}+U=-XhFchF6A84#r;aHfH#A@bx zyhX>u(}f(V`C~UH*7?kK2g^6{1hFsHO7ha&^FxB!m-9RKJz{s~U|sD%d9x@mHn&? z($SHxS?_p+u8v|xl_vm=bob8~A*7Y=4hU1>MAA}iO{018Zh%(N6m#8LvDf?`og?jv44Y&Tikxkzpid-~$A-Q?2^|E=E-z4O$}| z1BeJab2Zt$3K&9()OTwB>^;HzUyf?=;R4csyG^a&zh;O0sWoV7yz!?*&-QCvI=b5c zWhf`Pn8#`pK*HlW5w<&S3m!_wD2;Kqe*y5-uNCvzK^#Z?)o>n0wLRZw?2C_~lH>>C z>x^4*kBg050$TJ z|M5OiFLc@LrX37s2B3LNo)@i8nPv^pR`U;lUjFSpjUqW*fU|8Pf6#csH5u5^H`hR)jo zL%&XdVy28i?Pl+3Px^QMKZn!}?(k1tCcYcfFWH7W1%F4*%*zwY?GZpypd*i)H^?A|Q7$Zd#CZ0BO9DzpMM66xEMGV%fSo1z-M)81+Aw_kVr^4ts;PzoGKI z^TzTe1-%moUC(CzJ^d_Mf}7=*l??-^ol+hi-Z}aC|HY3c{h$ai+pwa;RgZ7>lI)wk z#5pYc{oh$bN2;60?=}2phitS}tEjAapM4Y0gtw2m3-8_S(RVXMfg8Lgyn#^#XUc@Drf&hF0}ke>+kwUM7fU0X|WEI=pkx;GRLd5HcS)ZL9L3^}f# zVugmINvct^0Z}sGY_HOrpdnF3#hACQ780kXrZhD*qLy`_mH1=IRs^|(Kg5EF!#J=P zs7xPc` zVOiKCem-x#z39a+lszYlWz;O<;ORe2-1tXqH#RMKi^ z&zQ5BGe^h;=qJHlu^0dDd%SLW-`An~q$>H2ppZ%PV{py*fs0KvU>G$_45<3Mn1y~U zRQ4pH&Qsm|-KmCaB1A`=RX_ZdS+9JOrD^8HU!LAS&b*Eai-soezz>5~LjJv|sAyGf zoPm_4l6J4a9T8kSy!R$1CcuHrJn&{}ta@rphA`A;$_*s6WgJ}z>DYgFwiLM}hE_4% z5#!)|l3lKh`|jb0G{xP2zc3l|SReOV3-^PG$&!N}--^;GR|`5}ye}qT=<~H+r;tNj zRaLdBwsyjkN-W8_nl}nZG&DS{V|CRNQ_$GQS?=E~`5%AUQqPDqk}6P^9vc4`ZeOpa zsw5jsd9pi4MovyXG(2ptk0l~gwpgg79{b@bZWP7~;EozRzyIZHzaQ&d$A4U}w+nYZ zx&(d9q#n4X*#C`&gF7y(yu2BM%D7aq8#FXCL)O>VHgtN0Agi#D?w&s&HkPEr6J2~{ZF@? zN&$f}0=)KdUqT70o7LJS{?m$rdYK|Is2gCg!%%`klh*N)T6rU;yb2;1WG4kZcS87Y zUxPos++0#`AWh(Ad919g&H#Vy(ZOZnd;jr7SvH4#5*)%u zV*dKA`^U8uaC!qjjU3_*4i1m+-SH-`k=(!~eJvV43;tM`!_j^*dG!3>hXG)@%w_fL z?b)!gv9pSb7=SY*p*FYj4-Nc}r>GVw+zpDt04^%@bNTBRzkQAzY5w!Uq%+FOn1S04 zpgl&v5#!#*2%+EGj)G^ERKJRUW2HN~!b|M!O87M?=}Z0t!AIKU4B1+5n5Rc+XlRyg zJUyQafvYvbcKf-1uO&1Y4TbCCOZOruL-H1m!6?pN`YCzp)j z6nqrO`gQH{%@P}pPW^tnfBJZYXwx_0)C9MdxzE721zZ%P{u4xDG& z@y>kGhTf(4`bL=O7FaDfL2^3An&#|Q;t}v?ZOxaSUvN$Yo)ML)QBXFWwez6+t1CS> zRQHeA2gK{kSp_c(HM106UkvQx;FE`Yr(d{^Uz$BbjGwemk2TqCc8BOzi*IUNuJ zIT0SRg=@S_QvhLS?!L0u*;9`0r-Zj&O!iTRKVf*oYa-f=YQ|YkXsKrwx+W4tb#3%E zuL>ks4g6qU-itEWKanL{nNw|Y=+ET8TK##tDS#5E`!G?-1luM3klX0lAUE7(Rik2N z{$;GF!C)>a?E;chxH+b4%4~>RnQA~ilQ(dzfi$x+3!V|Q8?kVzyvDufhUQy{piOh- z9p*d?E1Qqfga zU0YpopB$#wAE(HfowL6?pS7JS;Wmouh~w#SKt%*BpB^&*UWZtIVJNHHc3i+gkp~5y zT<;$t66IBl(=W$M)Sp;Xpgml#y15Q*+5-ho=eOA<2N+-}++}l0>n+MCp*o=xN@tGw zI`AjUvmZ`}o-67bXOmG&b%@MXyT!raQ^ZizMJU-Ds}KeirjQ7m-O%HNsx*Jalw_sZ z3OMurK$N-1L0?fq8~H^4rMhR2c7(XoXEu$VHsXuU_V*-?6)o`cm9z3@r`Gd^6P?H3 zdHFl{Hk=*Z_90OeGYq+JPpXTuU%}e93UjFfIBt*MleO!*5)tIm`srZZ!NR(o`^D$^^HX&Ks6?br4l0}j zDk=?n4Q>-5dian)VY3OPlk0Za%i1$*jC@o7610@K5V5_x-MiiE34w=0(_I!GGig*c zW<&%2(d7o>g)OQO*Lo+EGd^IbhUzB&#IWf)cOD*jiN=?1;)Qfx;%)tgmE;tBH=YwG zLH9eKp|+>I`b>JjsZ|zd#aihCnm^c7SAyF-uU=7xCNDd>OD@Po(E; z^N{o5j1(8pOr36i>0-aIp~@)ezE?!t?p?2<^{tsF3!?R*@Mg-_Yz!zn;(DZ#&iym#!zqMa@G%ZC!aqL+0$MY-PD9pOFl?4Cn&O`7fronKjf zbthszhabR%+4v{xT#Aw=uA^kWylPIbAE|i4u$GFS?R4TPP&T=6_Z)0f)SPg~v#jBW zls@nQdDM&z19KmR^(t!@yq3R z1<2<^N-gm&EpMWO++1=TUCX_j*`@Vv`(Sp^_NHk^ypPYEim=zhF_R2O~+3e8w zSSkL5=YD7Y{e}82&X{DlA5s z&CNghST(_)fAY5NgNHd1@HQZALx1AR|V~_gt{EGaSJ7WkS-*ApWAjng0Ewjd}iZzcEUsR6s6~Z z?$XMYt~=OMumM!IOq9r-oUtBx>2J!-l)^C~<;&89B3{Qt3m31|%V2V(+>Jf*&dbdZ zI{}JpKgsK24F;p0*jRYF$IH?&N1hkBUS7{x{RnCc1Q&TkeEfDgmkcVbI^L*P8#nbI z22<-eu5%c+=i@g-VO_9Jbh{WlDD;4~c`@ZG3-ymTu1vFr<6!Mmru|?)9O*r?|By%+ zPRx=y$11Mvrc!NjtR<2RqemcTt0m5HNwd-O`4$#kQ7>Q%Z=?V5X#Rk}Ssb8B9*owucLb)_i=ZnQ~;`#kxVq z+N;2Vr|>{@wnEQE*Gq&pB&a-Vj?SHDsM84sQY;nD#m^4T>^<5w9d^yrUu5#QCLR?gKOzOuIa!Vgc6`1O<%bd;G<06}zDIri+OFvh=p zy8Lb(-DYKF)c{4&$dX!7%78^cWzgfbTA?0%p@A_G?)vLj6&`=KiLy5?yaYr8%-uE2%blNf3!e3k2b9+R`3Dk+-{m?xUKiJ zDP5~sQ;$V;IpsjNX(h8cM9WMBGy@8TPQmA&AMBO5udRT-Uo@d>=Dwyw2(H-{AvWFyAV;pV0a6>`;2>mtrY{zaWQ@ zX_jF&6w$3+T?AF}$-L}C(R3~_Ol%#hIa$My9p4r%aUMuz7D(=}c_L0yD?D0_*Gd*6 zXCq%E$JQ76t=0)TOX6u^?pRJWhytk~wTu1SYyW%VrzO1HsiITwLlP_u)asKzNCn_- z8uiqWSC}8W^0=?-u2pc?#x@t$Jdt20AV=@~cBoKh+;aP0i(%=9APwFL@~kJg;K zUlyxC{X0ArmWy00Z`d?R5?b}6b1tyMEL6PYD*GV)ni`AV`|dBRAE^haW7aX(0+YhE zaS8@^e&sT1Hh%=~%rltY7x|j?KI@r5(A<)5-~)y-Yy<~N`ib=r3TNQwRyA2%$X7?g zCsFcWh!_l2gR4DNw2|^_K5iZT0`}{@B$qOC$`u9AgzSddIRem0w955PTS;VGR&g9= zA1zRQxgVa4%xiqs?(G(?BXpMdDQ)gN^5Zhl#LsbaSR>aBww^@y(qFgWVPk9EE}pp) z*SrBJOoh&dJekWzX}}Xqmshvew?YX}NZXkzl*;`R2(-x33_?RZ4+Yz{yck{x{_?8x zYX`mb`(f0V;;q1Q39WK)B}^B58~1BgscZi`{4m`me`yEH zVPffpMD;!q^3AWOOX(ybE-m|KAp^gC=~smdm;J}!pK@9WE?7_{iVnKGoTw+CC{%0( z)qG5{tY#o|_%eYn4FYfpKT)OYX@NZl3I=M0;)^3O10QrjgnGyOIE!^PD-64~dtsd% zD|Q2l4ZqrimU>+RB1m-I*1_oM-OK9==F?pt_&(Bed}DwD^qA7jHGMa$e&Vey)bEGM zlXd9qO04;NMv*&3bN0&w3(w0BtZ)iCQ_= z{_TdtlF7Q4YO!-JTcP8gW~g-N_HL~(U(Xu^+f+jbA5&PW&QlyfQdg=LE-8#cEf}Y?p624aS1bQTh^?2<-mzL}#HFklUGWys&ncIT5zOwW9 z<3_;Z(j9`V75EtXQ|hBF^ue7%EtX_+h7gmWFXVypJr{U_%umPe871&5rak+R+6!l(uz5f}*Xt2A`i%OF{+@bv)UFh2H7Wm6J!ej0?&`s!BLeJQ>Ky1Q8 zeln*o@JLbGf$mwSEm&d$*LkolWjp3Cm*b{YWNL@ue1q>n8DY+BG;;`$qn13Hgl>mY zT(4v1A92zbok*_*3t)$m=n&QD9GUt+LqLx`cN8X+=H*A%a+G&vx@|q17EWuQ@xQvy zO&*O}w~0v~6%g@J4FGU1QVpYYx%wpO5NY@2Wy(;<=6Lo&@;6kOtMz@Ybe&y#J6}U5 z0ccABVtGo8nDj*>$+Z~CoOK#vSgQJ$;6rcyuYykW-c%h7Qz*8gdjlWUnjqC7y2$U< zh?nEA&$VXA6>X5j54{ko#XHYu!Q0KY=~$9p|NL3pqGoY9Fa(_Ch5QM;tpTA?VMkj9 z{}f?<9Y_OeSL0)g4j!b2>hZ5h2<-;t&K#}2p1TIg;aq?UgvTM2(tE~nmo{HMeW-m? zg;~H%&c%Aa)hOTEw|WS-JyBKHayORUz{kRfIK)HqDBq!fd-RjI=*)3NSI5($%fN6~ z`Ht^3hvoP`+gfFJoqoNe!gsfxD`W<*0X&Og4D1UQYg)e(=d&~8+juFjXR;T_rf=b_ zw0#&5q$%M$8EZ#Rb6O|hAX{dv`==s8mVVG}m$Ms9*LK6&MXdBF1s9!2j!)jIm-w-; zctMo(B^p0!g;CJFX`E9L34Kzx3#F7Bmzlk6K&5H;u#ndbbr64voG2ZuWOH0aPwSaY zgaI{>jz?+Y50*{2y|*l%j{?g}1D_NSe4`4zJN!q{)2$F{s9SkyF|f(zEV%7AR+_5O zLeS&hNO#zGlo+l!w5lIs$3M0Gu4B)jKha`&GW>}RE*49_h}&&$#IB#hgZ9n<2ha!1 z+X1TPZY>)7IxmjCpiV)Ug!FztV3%DvW(}|x*kC8W=Rle!Dl-QPKx}d`#E32CRo1xbV6N=*hXq%MMNnydCO7=75o4B-92q)ns!@lAXw7bBrC5>!}tczfxx{gCZ4{{!~h$L;)MqQM(A4COOHtd#9ZXbcxiZ@uN1 zje%p6D2JgCz6~4blPk=$FOgKlKjHDJA`2b3h(h_q{ly_2-&RDh=MPIsbw>N|E zxt}l@ISg<3`G+7*>S?ixg)Y5i9__c@p15c|B<-7r+j9_4i5fI=tf{V_ZWk=8X&io^ zb0O)#m}~+v8ykT{8*J6r+Fic+Jg^D*2G{?!$~-H(i4+hx-W-UeTAy+7Ti6ATR)eJU^QMNxLmA<7aBGo%nS6$i;7Qr!Zk|$ zjApOS3pI08%6}|@(o;`s-M;H3m!51^8m$djN#r6O(?hOnDc-zdRyll{>&M_nd~qng zdFp=+=X^8YqOUjw+14cybcosQ0qV#OLMoYSlXU*0B{q5SKKk`I{N%WJj>6dLg*d7- z)2ps~Z+1QL58zkOnjQj%LhD6gcvpm}Uq!fTU>J#9fszlx!8>X&)AaGA_M7G)#w%u*q z6BbAPF>;kpiCFqR(Bno{$86kC!#xb|IK90rFF!6c$`VdXI!McZWjWuVjg99ik#07; zL1FTwK|+zX=PJ{2drzld`V%`%=pBl?dj_2Cj^b^J^FZOOM2W3O?6c#zb!4_FU|aRV z=ZCaIasPacLBjR|Qj_TkNt7yYwaZYUF&Xj00WyZ9eFF}D^B?Sfg*dIs3%gcF_dN3t z+EP*~deNTR1Zn-IZ7#gKggos(7kAO-$UtbABLd%l%;1pqYS8owAmvgI))D zgg>ZU{M%VBq3~8yCfx5XQ$i;l9cs6)Faw)*h+P-&VxWvK1DKMyOYc&PwPHKnQ$1ig8#n_wI0X_go;J?Q@Y>9>FO>=(i!i%i zm;{XsUj9_qNw3}UBghThSkrZCr{RQGTw7m!%e5`pux z6LmOQcW`3nGGqe&BfZHjk~KvG{Om}w2vve6XXgr?sg`yrNKU)zAwdKY-593pB(BThb%8g60k^QsqXX!kz1b33C+l`tzjdrZG z765y3_+@#S5whbL7L+*B=l;V@L9FjxVXW%oAlE*4VZtf!g_zDFUJ_V2cjadpBR=&S z;M0v?X&%;e_pn}XT;RkJ-2&l6TDI~u3jQDy%Q)(P!QFNE=@6Z&)3_F-Ox*Z`8Nc1i znV;n@Lwotw?8})tO=%a-Q{UVQO`J61Lh{WE+^AZi-sdAbO<$C`~c)Be;m&i8EZQ+ueU(OZ)pB-3rx`@n2#E^}Aj)$8Mbz?W{3lA9zyVT7mhwy!WLJ5>RqlpXgr_uNX7&!0sf^Cf ztN0`((4f=oV7Mn%`WRSuo#ia41JQ}^$%B;AzHOt^j8Hi6?IW4Ei-RkJ=D{RyKLYsZ zwLitD<#4(W;HgiSCqsd{8mfe$6FI+~Rb@1FW=`)BH;NIMayRcdAN#xfe_|iLckm-x zX=UZu3Qoh%rnqG@#vaewc#5$CmN0}~Kc5mJT*d(xYjJL(DdC+H3j>3JYVSk$aA>F> z-%vI*|sn>_{LZ9XC%)U80v@sd8;B!hroT3~?frBk|dKM>uPNC<6Y9{$MyFs8zhFOnb}cwo1}8+;{*jnWPtyhc7g%r-2e?@%cxm>e#g9X-?8(cyWxm%Wo&IfQ7;SKBb>X~ihkU-`9Snr z6nEbS(B?7ZGmRN{C~eCwlMckZq448Y)_Wao8{S}Eouf&8XcY*EfWG>uW*gI1{#hZ2 zH9FdWr6XdNQvOsq{>|a#;CRVO5%05m=VoLKdaupPcB@(Cp7*wajzdZHL#_NIw9zDN zmXQ%hXA?r*Km&T8yr2cRA+HxbxCv%1N>H?04Fpf8(&Y7Q+be^yvR|oqJ@>;IUTT#v z>g>L~ z%EQg?_FW)-?;NSTmTaPLQV!1Q*8I65rwRnT{EuJxmb5GegCHp;15Xo|nv#n`GxkP( z46&s1EOw#yY-kAF+FsSe>Gm+VU)EV8xebd)aM!JhGu{(p*VB8jA5s>n`*Tl|?tkhJCBdyD{bf^|9VpzKc z&lN-qRdRjYr9H)$D+xE7q2@)l@?$Bi*0YVD`jC_x^-t541YlM6rDiQ7Utv@p-DM(- zQ(d8VTnL1#J}p0Vv(|gUiUyhUJi^8@qR!c5H^l|#%1?}!H_lD2l*0>te?460t3}AUUergQ`|K{EZ#5I?x!tr@ z#|)C`#OQW31X4Hmcg4$?4%!QBzQF+ldNeMJP!wxz&D0KTdat z;d{>y__;|u;L7)#u`W2{8a)+lT3Koq$}A<@f&~fSf7a=k#j+zIOgp~aI&a_19j1~N z(A${y80oD(7Gc4RaD%1qKX%zYLIj9@bUGDD4O6%s!lyEXu336U!qWaZ&OMco$1vgE z9j{Mk+RY8CIWb8`Ln`buX{gbQj=<4wz+76%0KyA)JctTW?_u_ z+X={zS9Obayjyc$p_FjLz%FBu$E9&X8>g-;VLXqMlAnM6fT$LwlOU%E#<_@Ght2dq_=-m#6FKDPb7w4PqO*Wq5xem8kkG_{rV+FgUnMjpuh z3Imr!ui8jg1NZsgdzL>PM4X<8W6U!z-dPRa_vG2J-gU?q`({fmX}$FGdwbiO*{iq0 zO?O+6kwi>Cef!9qV1G8R4{_N(1dEv$5RigNc@1K!uHCBp*|cmvY01;u^`Tp=6SziH zHXU?6CjtHKt?%ToZCwrL)Rq{5Eqf6UQ-?M3%UbVCpeq@fB>mePj+x27XoYpxCu~jo z+cyYxiJ)94*DXTMCb@E`0NhF~vJ%mgvauJ!I0*WWkXf-fLMk4W6{6A7f2HcF)< z>CRQPh-X{?5T~mwiaAFpHW^!8bbc0%6QEdgyLz7W%VL8d=kq76lp<3)ej@ZfUTHBhk!Y3x1>mZs{Ni{MSCHI=dejQ{Wa(SoOCjVe{jgSfL{j&dD%S@it+bk9APLy)9GXIt4^8$Jy(rJ zuf{z5*=(&I&X-uV#&@uOJV$2;B{iZ zq^d~Xi*|}S+4geNEY@oov3}=c)*5=J!vwBWotfo9~%Nu6!suUDjDtHW2@Qd?;Uq-#zD-_&uX&9^riCYKfY|c%z77!kzAKxx;j3rWM(g{l9%z;(WE0 zSoT{$5?ny^ERaxyim@G|?Xos3Ft?ttDz?)}YB7X`Z36OjGl*TTNl`Tr;~h*A2)^6U z&2=x-ncy+MXAu^yWK1lw`eM*{W*%AgjUVpwb%rrq-R+*YC8&ZYAI zID6~3DA%oj7?BuyC;`c#kp_{j0g+A#rKAMu?vx>vZV&-MBt%NOyHf$_?i{+~y*YcI z-?N{6o_#j^{e1Xig1PVex~|phyVk!Xn#D(2Y&!cw3y8Md>_ylGn4}f zf=!VT#H-TfP2)lp930JqYjL6AjtA{yi;v-q8xQZ_lT^I#UKTMzrc>17fDyf|g4~fF zio=M{NMhhS-63XT^{bq7)LRj8gy+om1}D7S^^u4d$2P2nXB1t1wpZo&3jNS?Jl%e4 zmwP3(IWd3(Yft7_@J9Y1Xz7>zwcXc-bL&8P%~VRnKA(KSqY(*kY*k5KYc5|KRf`lQ{V?V)l^ffZX}0 z_fO;^uA9!m3HR9t%&(k;Y8f*fc~Ay$&T9I9EW>}xp}N)K+!w{Xk`7Y$7|nH_?s`I| zPpqbtRvuP!6-xwTizh-N@a28?ok&85>aZy^p783!Q_y>z6w`H~P!o9Lhwx(eqn$<7 zi~;s@vi6dK4)Wr$Rsh4WbV|r&J&!%TGOL@1-t1P14`of<#VQ9cjKA~gLB;S4yPjrPJVJntFkLQmu?5;lI^U{lH#n7eR?;4~ ztpDhfdt)XHzvD>w9bVUcih_bhxedH)OErH^K8J1O1n>sMK$1qp%0dHDV8 zQp-MMsytv+y4m#{xQJA-L zr@z>uKt3jv0||n)Ir}u|VG&knVcmW#0ki6$PWw1E<&__mad5)iQe6bY<{tKZk zX~Rfojq|pX)?}W5LJJ@_R@k*z@UuO0ll{i#r3igyGBGw#b@3TySdGO7U3glVHqaa89-jdfrZbe~)E8|Wl_<2)yqVsL{sR?QEvuG2G$Mx*U zr9lRy$J3)cf!K>(2zrlSmc#QygbSf~v2|6kHSa~PW!*fI3To@d+6TlIAEO{v{1|;~ z8PQ}VjbY-+VdZKS#xZ9Pf`GeG1IbU&uTKw~EHL-FxJMtoeA!g;3mS?)tFm*knA@!|>G?&j`bCxB z?J^4Wa9s>us>?g5B~L;FD_VWxumhl|Iy0H{&(O|$`CYxmKxv{Q8y<%k%zN`r9g5cC z`iwNWqps10{UsM`JQb6x+gE_`k)^+f3q?Bj+yr1|*ci40x-J`oEM|gCGt3u);;I;s z-KwdDfR(rTDa~ir2BQ%J^`i%tqe^QoOJWYP&c^yz)?Jedq5 z4{Uz)(Dr1lNFbVD_YtA@t7IYGbsJslsYR2+ubwqO(M-q&9DneIbD%rKxgZMGUG-?V zts9ylfw*V9$8K&sN1m}bHYmhQ={ii?bS&p`m& zx9hRM3%Gi4NR4_<$iVd!tHR8U8WG8KX=Z69_fGN2<~)x7{*hOxKAk2jnm`r5qp z>hw3luO%qm-6o0xFr+}m+QMm7?C2Wuf=%Uw>YaqHsN&xzwMR>;3F?~|-tr!8UmvRK z$yVzhs=hsVqEt9Y%y^&khf>~gkLDwx4nsO`1YR2NMzq=`U0s4^06FxkO>m<1E`2od0@s7J=H12GRl^GA%ZbGuwd)aE- zY8my2Zogg%cEUE86DHeE$leV(X4mniO5z;J(R=ZV@kqA4n?cd1hE{eySW%_^?zh9SnyoEnL7Yw73j55TgCt{ds0gp6<#7H$KyB6~11s18p^ z|8VUjP=pZR##H9Q^L8ueln?4(01(eaOyHY=@YS6Hiy7f5qS6QgvybVRNabKe3Ywyc z=}hHzRJDE!3)sEiQDd!n!7-*&YBVhm!p8>CpwD6}V9y)abf`gf{zxsHn4LSu=U^hv zz#41Mh(!<91JCgpv)Y0;FjVK$Q00^1Jn|SK^HlU_ps2{=L^pv*12#ZQhmKm12J7e4 z!)Rc;?wWPyOKlv3f>xtAj~}SflR=PH%9?Cy^IABQoO>Tomq-LfYz%yD1w+Ri%nbY7 zvI@uC`?inWJZ@w+Le@1^(ICGm*~9gTmsI=c@x7~Q+TYCU2gE*29FNGQ)tL^Y#NmDx z9ezs|9JT8fFd!y4o<@=|L<36zwbfoY-@M(fX`n&HgVJVBD?8{EUC--qKqR3vY09Hm zN4m7bLd4RbC<3_n7f8cxD*q_5-nIVYl#fIIri{;Rpxh#?)dDu(SX@YPQ_VY!x z>1=u@zOfs?z|J6iZ85`hgYt40{|ZVV#q~TSa-N%427pF7MeQlYM!hCH_^=>eaeQ@I z7yxd_TRnJk^s$|XuqR1I!=*4QWD>AJ(v_evFlsCVR&qAs-rR?nPD^qtEe4YEM}RxF9%0tX$5LH<93rK2eKTw%fQ-u+1D{Kn-W)i8+5R-Pf$us^0QQHbh|#a>|-?WlvVQLR=02Td4_b;QdNa%|7G5E zumpJS+HOks7g>vKDCMj9hYc1%n)2l|Fwkox9x2hukuv~~5^s|=FpOgGjSM4xF6-Cj z7-e^3urm;=*czm1DlqNGTFb@!^@5$`Ti866T2|;pq-8hqBn6+VR*~xCf-Y=QKY{We zG;DdI+na#4YAgvf#Xc!X@94Ix@gi0(=vi=xA|*1)NGR?VLTyT%XigD>28&s8aMu0I z3fd`0`|`F{bMok?lvJTB{B`JxHw_sUw4Vz3p(*2iae%~7!d#y{u^DG`vtJ#a(UqUA zD|el3Bz-d+xns^IlYinb%mBu5+7i*ih@|o)8P4`sQ_|G%SzuP=IBFhmKY6)Z?R(bI zQ{!7DveGgt00gVqMQ7z@6IilNB&OBWW-Um~Q@I=rKY5cF1a9L3nhNb`9Dm0H&f^?I z^gEl3m6{}DQtTDfmrgFeU&kq5Im>l>X7c9TSE-U{Ev0-D`C$kXemFS8^d{=NDcpM+ z37Y+?KPYbU(H=l7FH7}}u zl~gG-6d1U^%yTj&Z1OaWKJz>{-?{?4Zt>uUnLxyWh6kQw_;uZ?XaKX}?K@lW#+Cf7 zj)DfmN=ePbF#_lk0i6q1%Gsok15-22_>VT|F$0e1r=a01jaWP&{2ZnFP6>T#|rtu(0E8IH#E z%R=v)2uiou>@n8Y+yK(7(1fP(j|USI%^|;|eGCab*8EMloYvV=Y+zu%qD=}?0C@aG zfiTZH`Awd2t9)9pp?C7+(lK;=sUz;<%ZyeUYM_`Nk|9qf*VYBv9+D)1vj8yu!PG)j zjr1aBf~GY}&6LifhU9!7JbP$E>{=iNfgM*eMZj;K%P_%iGsz@3HSEJ^NRO1544~vk zTZ`l2$_5-CymzyYJN-oH0>RDo3DdEw?`OLG0|WtRp_KL362^&PLl6LDMD+StckDaN zxBE2{Vc+fFxTmSqeOxrHsahp0( zm6|0fzh94Z?(6iS${t57;LP|`3>Vnds11jrp$HRynzBAn0T=gc7U(em;VL$E;furq z3!NmRFObmhJA^^~$U1`Qn4ydmfX)bQ2RRMuzLTx}8TGjX3FQ&3hZA48KMA(&471lk z9hb-rpLSaFh5|8pt!m-D&r7>epBMD1ysHAh?N{|RlzLv}2T&4b-crs+ zAy$=EV4VV)0zJ0%A1l8j6vyIHbzjQ#hZx9&=B>QqtnE9n_gLP4t6nJW*G|%{{NXti z1gjL!A*~g?KhizjyCIAjE3bthD2de_$YtJ_TA`dJe-O}C1y7wo9ECe`wJ*OiWUTRo z9xr<2k65UirSppZO27o1%D^_rm4IAUs0h(y`p%moJJ^TpW?U$(G0W>z>?K_4sS^=m zf3ZvG5gi!>c7@q++WXlah`|+C2M+uM7MWNdzog`Rc5uBne@Ie05=7|17j zhs$OwZYF3Xq5q?^KF$-Hk#3OVoLr$f3df{9hX!Z5;>71F6Pd6FR*T&0TtwKgK&U|52h+BTo$Moi5^hLE}Jv!u? zzO{1F<=lP!xKF?<0JUc&nts{dP0y-xAo(NVjrEf~LTKr^V_fKmZTv@vYj;D)$>(eiB{`Yhu>9-%oRh6xzmd-S{bb zF9U+JiueV<<4_hKT2uD5%?;@C&F1V>Q&(V>`03a;u7?yPo--#2CDk? z1TJNTpK%~ik28N@uK*jK>E|tNHe&(O;h(dTjKKtOO+8I zy1j11#|CrHnoDpZ(4D`}wyku7UI6ebFM&Zm2@+Yr7HO{+)VtQJ(kMiM53f9}A%&c% z;2cF2ah(z_|7Z;TQ6S{gWSGRaESF+}AsC6baUtSClK zJLRD>iH*M?h<|G1S!gmqq&F|Y@gz8MZo9pX3vd&$rsU8_ni;{f8jvHXwZ04ovddNkH}fp zfjpqJi-4R?jASG&v!|D?%Z+2$V3bUhDJChhbxzky1a?|@A@RLIbB=HLgk;iRWBTRD zlHbJ+lqUu1^*Yi1U2zzO$H7j}0Xcspph$2kZVg#RHbEC;pNB(Ik5j56iQEI^2BuPZr)8W13!my^zJ=FR%m z-sz-Vo%SX|6~cm;XKtSzPYuI{>RDmIFTTrBT-zpzXg+dzefHVNq$`p>PVLugJBNCf z@81sS(!C@{`M+-uGU*;$&^cC(;#FH}o}G=j#e_54;FH8vyenB{m;Mkh`oZ!{CqUti zBc~-g5-GSf(Ud+{82SmHUGjz%-angl!M(G`_4Bg4R&ln--*gSxDeaMz9z)-Avj?uG zVzR;DjFXeiFC7&k#l3^5@8y6vb+y7JfA(o+eJASTtnjD6*(&+x z!L-Mb4YS@2`@tG^$)9DBFH!*_ViCV$ih%n5>Hs?^%K%O~ zjPkh=X6}h4rhQ4G(1ds;CjC&T0Wd+{q?!mZyS|?4dSXevQhh~{xJ#AeKeEMPZqga4 zScg$>Q9b!Rf^#q2-Q%N}Eet7wNb8I=O0+Ojeeaz!e40UY;3H5ecmfn*=8Xv!&m2DjSO8hsq=?FZD7= z3imscxwZxA-1n}Ew6mqubM?wH#Q6L@0OV=ad1}VT3vw(cB^3r`bRMMu8dzi5zo1$` zz`hx1cN<1|=64#fAy)|nT}-p+eT$sRMzTSUL)e~6Z$bQAa3++iTo5WWU7I`PRFisD zwMhWt`j=q?8uqUQNtySGvg*65g5R!w#6xL1=tzbu45u@ZVT2jCIv#|^+#z27vd-e#&AbaI$NkPW{o>0K_; z!KB}xpeOie2SwR~<4n%a+U9<<;7Tnfy3ag%jTJY4QOk9z zs9ml-_o9*ZqxPP=de>_=PXHUGe0=ux?2AFt#|cmb81aCY?56@%XyZ@C3b~nYBAllx zgy)}**F=%pjWRE~rx;n|q^X}}J>KtFq2b!i#tOG1YBwYP64lJJ!v<6{K4LaN#%urn zWgulkbn=|zSK74sR294X^G2D;p{GDN4OQ`ynGluTwp~?ZLBOqAR^(l8syGlAo85b0 zAYgz2d9_sVnfMAocNcv{_t}B-pwVFb`$C*Y|_As6Jb*ZRJk3amPzU4C* z`slfG;0e}+qM4l^ZnlsbT|@0n;y??2_Xt^)bkO5Q5!HOdQMoTU-}XoL>m~&K*)>a1 z-(?j#?B4!F294@=drG=&+Y0FNjHvf$3 zRg;J+6{Iy=&Sf)_v^w&9s9NJ*t}aWEcZY~p(X?C89Or_^5m}~Ej4Bb!Rb6pJkQ=l?Iq;wEl1>s5_#q87H590FfkI%TtmsFJIai>$=)wMSUMk`SwO%7K1-8CB+YTnkzzHU!~Lxcblh(iiO(F`x?i;&^6gT5 zh}+F7vKmHTS(y?_%NfnqChfATg9j-I&X%s1v4WG71j@a|)84wEyXJ~DUs-*@Y_gMC zc?ra@UHiDf$G*ujNARzZlNq%hvJI;oj}6T+ComB30|Hw+TD?L*F2E14OlE2Vw_S+; z70Y0THMT)q{j^$XPrL$6Q=fDXVeKoRA1WpvjG_D%#8_B;ae&OWs9-;!y)p*K8aLPN zrbiYr%D-GQ(VwKYemv+cE5>?UF=;Y&>rL(Im2Gl0;$nX)JYJRJ$a<}#2MB(-t&?sY z8=y#xOUKRh`zohH|IADwv~aG@CA-oyt;wZ?cQ*M`p2qJLk99UauPY~=C?_45C1nav z9%h9IosIdc<~FnLEEI zY_jV*`lZX}8&K;+3c@1sMokahn9xTnC(ldN!)+V4tD1LW#v44g49^U{C`nruWJ+uO^nu!(6C+ZC2=kA6~7zyw9@6yUx@Z zrtij^xK&Prh^u2W;%4|Tb-&;RdsjeHKoE1edRP6P8qbX(Ac!H{&MfHP38}*|=(>oA zcZRV7usbplHx26NuHXwjgKvPd7#%Cie{l4^?&mIfnsW1w|9H?S&Z1K*E3ENC#j5f~ z3!Je$WZJW_0oeY0{LVWM-f+_G-l$RKBp$q^6HQmGguf?|%dr9iYKl2G&ni5;d>z~_ zZVD9XUH%VqM;7sv+^sv7DVkkhgfI!RSVjXAlScoR@%D$~m@k{Sjb0ArGr(OK9wDrVVP4xNf=TMl|o1M5V&ZkTgt3he< zNBCy1mM@IV+sxOa>%r(dPj>y!2?!AvM+4*xuRh_x32=CMM@6%}tQ! z{kp+`APFE4&EnJhK=OWlJK21K8C=WB(d_TP?q1T_U}gB7@g1X zMTUA6+${Glc~l0RFG55ao#2OGm-?4O?pu*c+eXZsaR_Mm*r*$*&$&|sLJN`n+A?$X z*9SqzZk1!!1+@l=7D*1b(GxL*D3k?vz_GVbsBuNbeTy^`g(G9^DkEn8a!^`$RB%BBCtViPOsdTt8H-F+^cg(d+17`*_CSaS{*2@1kF@X=A z`v8cE#yLSCRZhZb5o6TIW5g2A9fOTE_|1@lT%c(wIiD5g%lXiN9V~K>`Ah*y`Z+m1 zwnoPMK}LWbGP*12)hdFcVzoUA?V#9@1=hobCWGT zfl4>plCgMYBnokQ2e2X95bp8;(I%~Y45ZWhI4B&(q)M2KD4*R9)hap{& zNF=2c%RM-)_QiR<1gcT+lR@hNo6!qhqBC%gZ{A+{TcJ$b8AAQO%BujtX<>X__LaB- zy+BpCL7SnjUYnh$eb^xdw{Fm=Z8q-+5z`gj*fmruI8pr1X@5=D+XTt`_o{l++-m^~ zqmpK!Jzf>BcBitZ&M8&c%G9!CnRr(!XY6>>2J2s$Tm$7NNa;*-{lv^25?3A5SN`nh z6!z~$Pch=j=!_hDN)jBJb#8Eo$ROduC>0odb$clqG(?!8} znMw(4BGMA^3SUpq(>y#*wl!xlB4nhFuGY^tOE%%Q5JATzjKm_NQ%_zBdAu47nIm%k z+zBk6>&n_inZ0Y;!y4%#JGv1MUkeJ=y!i^I&o$?dvg?psNxHV{0k4u$NaJPNjNNJJ zv2mn=n_XubYf4(wM1c*QQqW7W{HsNp@;sGw=SL|Lry;oy&%e@iF^WePFYYplSB8Fk z@w1I9I_TjeN#WPB3GtDuEaNEjdcF&5Mvl7xU-eF?}dkQ&@1uj)T0nrjUdzD(2WZc z{6A+2BE|Np!Q|wuDzcy`#VhB~fJFi*ZQ;cx|HBG!a|xJRh6)Yj3M5YFxGbapT{lbR zha@kZS?S&-JGZQrf&|3_+e6aB|%H%AO&fvS7oqgU7FMiu|GvD1}TGZ zG0?dG(+c?Qleb_F3JB0IS}6i7&PSK023$FB(oG#J5V+Nbb8*RUmmX!j2a9(t(`6^` zH#zkkT_h{tc-YovpihqoG=rcYti}9~ZTeSkg%%$X483g(838876Nb{pkdj&w`%Bf* z2s&@Ydu)tE)@)AUeq$Vn63f8Ts(bBUdp3h4lfMv#Lpn&OGWpu*|82)R2?S`cy2Y=} zF*l$Q3|_WMITR6%wg@P_$rbQSw_YxO?`G_}h=*nwHS%Ya!N0MH(cFG$`1I01S;}pH z3Y-{d@RDZ*|C2vAtNBy!nm@jkZbvE_W2UE9>pi-^sB5^T~hzP>hQXjE_%qw!a(` zO2RF>F?`!R+E9f}(0|c%MD{vjX`qyU~^0m?;xO%f%H95QA4Tzra5rhRP=($!E_jBET=c z8ylE~S}evp#Qv9C{rRg%Pc->dp>edZC@vG(z;@~SiVrk2{{j8~BlZ2S*M3V%25hyXPb1Ko=N0|K^< zH(HnB?mOvck%B-bD*xfJOi+90NB)wJf-d0{kb9XH z&_7@<1T>uyq|j%Y83Mm6dPrKbKzSHY_^ z2gxULh~LUvhn3#y0bmPwD#FSC+yU#q?qm^KQ5782h6B=fULyL zFx_F5)jO0Pa{oa2)6P)?+W-a(D5hD=a($Hp~H zUr&|t@&ewlKZU`Lv5-OKv@xhC8}}$_IH8Vu5A{$^7}tTW+JiaR8sxFj)mJG$gQQMevMr9iA~tKH-~n+ zaoKEY8`p3@bI<%!?ouc^Zn4|JgBNAyWuX_wZ}l}l2%Y+ddKx9_>s6xOT$ZSA{IZyP zezSj|^aUEQ-@ms!lMY_MvqOil70*%JRT9t=0lEd3goG)H+w{R2Wpo|b@SwfyB>>|V z15v*$wPclxXL0%tNzBo!`|4l`|MsFrCwn}plm88bpvUwZpYGF^*-@y;bB zc8m097jU1$bWQDS#gynYpVT++<$xd30w7d8Y0zE=rQEQqa~B4CneB$qaOu0@0(A-1 zELplEc<$!mKBw;^9- z<6>nAnO%9dm-6)+#N*kn)SS1b=t#ISH92+n<&Mlp4l6%GDFhjmQin%h)O!XHun^N# zsDI6ohz6=U{k+-Ejf%hNmS|v;3DJI$jgS0pViQGb-HE#?>o?Z^s1x(f+Qg5R=C*g1 zRZl}!0Qggl)8vy}on>rP$Du5oZqk+@zK$`!^ozCx{Wuct*JsO%2!VTcls;4@HdQau zCQILxJkQtT*5Hp($x#+h;x!Ev5%M_xh)E(K-yZ5U`SExXn5FtuDuS#a>|~{N4$@+> zl*4%r9=$wHX76RHbMnYIJxUl?{Ul~A29f;Su3+*bqs`lD3{{)AaHv>qOUPq(2M6js zW%tbK&CyHkn&2gs=5P{GFLv;o$CdDVXtzWXUNJBA%Lo5yW)N8kb*6UY1!x$R{c| zvyUD$hcKjhD?YItTT6(z4-yu+-WBeOT6A9}3jkxI@BF2J{ImV-BL&DyzFO{6}vq}w> zd}5)|@BT!IFS*A3qwgj?^cd=6L1ml2x;Aw^_>QEQ2C(^UYE?XhbClC-v5W7)LG&X9 zx@r_YTPj_t!Zn^xwjIulFC`shJ*a#m5txbrhzLEIu>Eri??by)cVO&m>2SgNfjKUt zd@z&cNyn1#Wkc47*`>tX?>4jEG5Hl>xl4F@7UBS*zV}g?19mD;<3OhKwxG=664Qz@ zh1sz3#%RN{eN%K(H42=-Ul zbkEH&)rwrZxcZL*F)64bMC{)MF)fyrUHBiA2cht4!a5OxVwu!7vcS;Ap#c$>54uMK zT({#@S$0mQN5y8m9ZJ=#f%vv+u07A{>ARJ_OrM6CbK+F0EoB;R)5}i*m|3<1dXJ3T zFA|`y$DqNpvA)Yq^f<{GTvs)Pnes_L`#F*Dcq~R7!hO!?wVBkv8aEcvD2m^iBN5PO z`2n5l3sk*8z{m?99za=i&$Fi{i;C}06F1%fN(4LRm11LX8jppBLr#U!tf!n*n70~y zc6L|9&0$Nrj#3shKib*me;Xj0sq;WaIZM#5BA{PL&r&dMwbjo-)poU|Lx=pzKhyT8 zYmDSbwXc|2aaD0GYm@t#Yvf_N1{fUCfZ?%7Mp_(v;mxAMp#-R`)!3H)qIsIQXV{b$ z!5UP0;_gd7R=8Yd*xe~1EU)`6#o@`K)^>rcFxS=Tlep2K>*^dd8N-bvtCAI^Zh&Bp z=0EveWsVy~D1!{qo?U&enO)RkFMud>&|52XQ+5vP=^8C}7b8n(kyZGwZSfRVW5hM}iiD z1}ver0BV!fl>-V&7KCbl)2nKJZdX3*&8rJcIxtyv?fcq53-sDj%^2Lmz-*C<1@Mq>EE>W z5=6=az)m|~*_ky9?7IUd+;*z6znGpB5I|vwZ3lO@%v%2(qga_Z0@)p|spKlJJ9mVL z<$vHYzGR@>(B?4N$o^TafLfQvpkz(LX(>IZ9RoPjxqw7v!%LEbx|0*tvfR`jcDVO-#3Iuj&I^ndLDb-i=G0*GlEIYih)p#N!;F0>Ho@_Px zbv2NkArdVpuXrDB5)DL9)fA>q+8#hdDMeKToYu2?ZY`lK`P8*xZo%E9C?>Vnq6Y0i zQ!1b<{?DvndE%R>;cs@?4!z`eH{3Gm0B;c#rt(Sb9{I!jDpabaWGhCV+r~ z>;#2Q;4h;r&qr1h=e7KE_N2e^hv(V)Kl0NgS6Ie5S&Y7EYWz@UkuuZB+>)U0`Lzdf zur=ZO{}lLSDWyjccu;gAc^9+5s)-L}Fdo=)>PCV4Y@%%eMFWqWf~q3^hc zGBmcWZn5Uh=e_fS&@la(ri1JhgvJums;Tco!(KP_lL_O8RCf3_@(h~yxm%#n(cwWq z|5mFy$iPF!Y=7=P*M69R_coG%G_bu@4y&2Z*T07cp}W?f+MV;B8$1~{CC%K`?N@n*Rdmt&$2A1cs{$YfI^*WSa@=Kk7Eu~ElS*|w-1Aynva*NDsK z8ZrA(`-==oJCY}kkuj@fF$7SMj;X3+XeoSfyo$D6vqI5oyu_tYUlbyJdfxNqCFpJQ zoM!fpus6#ijamRW+{19-odk!qa$o`ZVUWI_TUp$q3Zluw;RbC0X+yIaoA7>J^m45< z+Ke0zEW<2=hd^M;`!EWc0DvGV4g(sb{B|AtsdjIL9`$ zKa%jpD9BmSnGw=T>BACrL20%S>jH1YXb!|8bt(toUMNr_D#<|2x2Eq>>&^wTfvz2= z|FSF9NwZVO$1A<#G8K}4k+n|%b!CV|_8u;_`ecSMc>S3wIuYBF3pxemLmumm1XFCP zkCpR*q{eOU8yw?rFDn!%bg&h|1*j@7k-;=O%DO^iPQHObVn0UC|Lh<97uf_hoZFlh zm&yD0!;wl{uX`CsKY|fa4&NeUbhGj%M4_q^2cuWSCjf>I$`{d{7_|Lmo!~ z2hxZRP3JyA!h_!43Ka%`^?SxiMFfmnP8e#5|1_bq` ze|>wgI6|?pKu;|xVMv=}Jh%eLM>^B~k3d|hz18fAxE1lv#R+BP^ISEHofllD;cCf1 z)8+>-{H_GvLXE4|+@Ebw(}C2ulp5!*;?Et9m`PJr4sU+#z414>BS~Km%y{`eQ~!cR z<}<`#fXMiiDyb{DE~I*=+Ih6>r2bfs=83Y3B=U3RqE|(81%zDOzI6#@qXT-y`B-2A zNr80Qvwn}=a2I-RnM8R!`&FOg@!su|saau{z>b5N6DnV^Nf4~XfD{Bw!!(Y8EIrpa z=JlF8Qnl$9EjO2+9DZ9u<@=x0Bma-jNWg=kU_Y_OdRir^U`$_o&|i-`|HI@(Gtqkt zG_ZkH8XC!qX_WrE%ppZUOac#z1;64jm_Dk@@=KwiG@zP`iwM-bJZH)51@ zD|VQQjt)yzRTVHecs75o_ijJMyVnN-#!Xt?hd7#HB0^qfbp4mHzJEBE!5zeT+cE60 zbP@>h!_U(;sDxs78iW}SlKiZ~#LOHM9gWvDFkosH8vp7$JK|j)wlqylS2qQi?~I0o zm?2>liJNh?gKT<-VU}VDewZLLDG(M6z;EpD?{|Wt?x|t>-HGnDX_a+#S({!(iUm9G zua@5BIjJJW{cQOxxuL)iUarSdD7yRvcUzyo7%kpAtgxu$YPuW?WtWFdIgJ5)cqbdwbWPa6`@JTAJH> zGTV{Fhm+<|(eJX{aoR`=L>kX}&%Fc!S%dTwL~3BkQH^}poAJv@5Bw^cnx zdF`$ndh9x-y(r>lC?M9hdPF9!A8g2HZuI*BcAP>^B~`?K&6NLMs$Zg*l~o;!z6!Hk z!iOLD=JAuuA0Qc}YU!taH+9c}QK_*B2_B+g!|UcR-y1LWpEV33fa;=499Zvg z>V3F_pFj$~?vrv;BbCdpBx{MYBFw&2g5vUzc z|DFrif)N!tB)z>0zKws;LdQ4|STJeb(6I@87cBJ|4}{dZdXN-Fy-%C{{d>a;J@(f~ zXe8P^^yPNXQUKTK-CEetJV&+TvErkMaCgxh-oHQU#tk|Sn`>1;`M~gkqSvDfBYF03 zhJk$apcn|4FI*)Syxe19^6O)ps-`BpaP>O!N~U-#+Z}csAW*EJ9PC-Grgwg4hcW!?Ek%m<88Aigyo_r_D{4{Dbv&7$Tk6D#(3}J@Dn<&R) zm#rTU{za9s3k!yD6Ii0vcky8sU5IYYX{%=J?7rXt?!W2lziEiwPrk?b11Xv`ZCN&T z$-od^m5|pkV6&agFaa(_Mn<0L25}yY27J#b4>#ZxFvs{ZbBFa?QO{vUs6-|(TO1u$ zbn$C%()JG$r}lt~Et5LG@ncAS7It^qO&)&9o3?ltQkw&refOK1B3m!f$Suif@iGqu zN`irmwE+NM7#KJKHu4Sk%49N>N;1eI`8n}_Tkmf&3%xzd}Wcpq{* ze{6Yq8IaveOG{u-6u(|L><&U$tOIu!N(D3D1WZ{mF<@pg8f=ZPFXF>pRu%c;9y=1$ zOe*-c8S;x4NwKl9z>UZ0n}6Kp;MVvM^*}IXt3D7edO&7nr52z(0ByJUSls+Bv&F?$ zkZSQjxY$8fRFWzxQA;Z;c%Y~%`sS#+-Wv_}o6&D#;?PEIOTHxd|ReWNvUd-?%& z?&qWh#%OnW3Q+6q;yJx9UC{!d3nzu4gj8T^=a8hoR5*Y5g31G_77R*%N15>>=lS#J z(gp_U0L4V&QhR*h(7emeH>TYl++f~2Nos)F2#AQ}tgYGnz&JwGwzE^D5{ zxmSn;eXgk~$3aXBej6Wlm(@POxLqw7_GBpd%a<>hVNrcp0@D_S`T21sJqaDo>@18$ zxlau-68}IKeQVn^HCk850FkTc>$Cr6OeNxC?H?R;fr`(0 z>xOx1PwLU^S1UcXP%37fV=SxMUgz>!&wm(i=!>F>5Kwu*u1DrViwIfZyTh#nLT?Y3 zK${zi* zsfRmd@v(77QMI)~9;b9XJgS=7rm8keGJvkxiY+TEQ&lS&?k6H5O6HWc-#XkHZ|EA% z9iro9*E~Pmp%Zp@jM!dG9rQXP#tDt+^g7X;RR3&UNgoeLJLdNzO?CR!LxuI{fjV4k zvNac?&XX?`Mb7y6SH{$~h5W$lU%ylSt?U}Cza=J6P|F?(M3H~F^c)DZbvFluECY$~ zH~PyDQtMc`p)6WOV(l}|2|y%S&901%i75)BUr_sa+*IjoH5GLtowod{=a+p?AC1wZ zFhDi-S6CHeXLc@Ah8>Jmds&apwhowztsD)L^DnyGt_Gr=Mz={TE-UdB6Koo;*sPO0 zvi3g?Ehm1Cuw|F^czItqoI}F!^7=yOhea|$-2jRgAdj9f3I4qT%nR_?*!u`~) z%3!!#421PE=b<3mvfVGO&v{cm@RXl*9u;Fxo>4ly_q=I|C_Za_CyxRRtuL0P7p>$H zTj_=*bnAKSu+4hi+$VwH{YZNDx7;9*cuS(cJHb?7aN2}te)qX}|?p}^j5=k&k zyD0QL8sT+5k|MRDa+z|D0i5fJGfMAM8OO1(AO*3uMI|At1gy%O2Fu#LKjs zM}B6IJW>?A((xd!3rx0o2;t}F2YhOR_^ZDa!+s-Tw?g>;W9&P_n%cH#RTNPHQEY&8 z0g)!XL;`{c9GZ%PbfqJNPN)G9q(~J6q=a5XnzT?t6{LsWLkLAW37r6;yv;f1-h1wQ z&ntiY{EW%od+oL6nsbaX$7=f`Yh=#kYwFw5-cEgnS)UJc@IG>3LY?-;0tmmrM_U~i1#^wL)a3CQ+ z>`Kh&s5Wq?rLHQTt50cQ(|ORc`k2d~V1yCD1?KM`TLoqZLCcj*XP5^mU$jU%W7*~8 zmR1EXl$X2lpJ4y{ws*;e znMx)~__z!_PPheR()*VEDCs!Wq&BKBTOa+un(zpc%N0#g-Z1B;k|};*p8W8u{qSUS z>t>SKa0+jto1y)fsmeK-j)dJHkG+wbcEmfK^G|MqR!V$;(zRLRV10>Oe15`f#Fe7I zd}SOoJ%}s_kq)>;NB!F^QriFOaSr;QwB2kEajAu@@M~W81?9WI@;?F}y==n>W11*I zc^x-;UNSX?bMbzxChVEDP3uB;2iAMr3r4ooq;``XaieSqh`KkGn$$rRIXzea0s9)* z%ou+cgUqARf&DA$ZnXN10U6WdA7_6bv0fkVBq=*U{$ChOr8hLMQM+pzuNcN4X}tb3 zkbaxg;zt(hv&|AVC#!ZKf4U`2^;1%&Dm8_#%VdSToZ!7XTwEHt;q=bq?fGxGsiqKL z=`svzQIYiDd6A`ys@arkMSadkb0Q<=4O>QN#ABvL&=Daq!K*%F`!;d8+FzG{XKHvi z;ldf_+ZVvUUm~Gg6Yq~pKOn6Fa=T#wk=fW_n+q1~{5llq=3vvL5wcM3+|pmgbB5W^ zz`^IiZh!IMLVfFWhT4k0BC6(K8zheR?ZX|>wt+TmH5mKj%7P49ZlB=h-f$id z`1^qr{xjZh0Za-gLR6KA`$3%cixzWD&;x>ASsOc@&9(TUK+$mzc~bJK2Z-E4>3||| z^~@m=Um^=>gzgv_w#68+IB-oPy(>KxnN25Z`3v=5}l&Bd@Ta zwxJuJ(QLG^ZoJ;JXDsgcwaX)hK`I&f`KseE0*UKh?A&zd*h?l~>zyzRH2Ssd`DVYY zZj+5UzHhRY<|1S~b6ZkMp%Uv)K)C%tRSyO0ni&z0d%Bi$%}6HC2lwHyK2^zw$Ds-# z#xwVy6z!LPYe_!7$xpI^GQKj*oV>izRaI3{vPQXI@}hnO-DrgoFp&?75K{dmG#fZY zAg3x@Y_$v-%J9jL7{a=6&A4_-Y+MWc{3;OZmBa-EtoetC#j^LyhDG4b1&mV7eOdJf z#N|r@2Xi#rJC*q8c=nC9pX70Yz`ZK~hjqQmhm0#&;-(<}d`Z#2vjyPzRZ+*uj1 ztEi*?WvXIR6hc-jw^T!Ip*N!#qt(nj0t+L7)IBnyVQ#|M1vxJED}HSXjVv2KtSzTr zc_Z*B!L_ONDmm#?GzqR5`7bX3q*OG%h(h==Eo^F@eor`W+A zaljdR?1driZ*N&TndG>7``$`6xv{HZ>dOSAF51|LINDvvwhffSE8CzFYVkSyq2}VZ z8~*g32^jp&bZA6zr!I|H@+BeLNx!FM!%nnhg(If%!xoa;{YjZ4bbV;@k3HGyfqLT! zQncZP#;sR-PLbDQ`G9-`H4*~(O%i@Qd5fOcDS1=Xzv?#i?beBvWorCdIuA5cv|o{j zzjD?#3dsj}ud;S+)18aXJ;}aGy!0$KRlA{jx=u@XN8ECFjN;QT`UXJie!m3)l~f-0 zaSU9WZdST`tw@pNQ?PV^5N&5hj2>G-)p{kSIP1c@VaO2NcsfLc3Pr^a8ST0n0zM{L zNNKs(T4V>Fy?l8KMD0z*f06wJPd2J}oM=hBkrASe`tac*ny(;@V;JzKE_k`Oxxkj> zvHujbW;$DPT-2Oj9Oz4mCCL5Uf-z zfc@j|N*jPnfKnZ&0!4BxR{+1*4?#g}qN1Aip_2HWJzh9cp;}8EV75Trrua{g>trdy z`h|w?eOV)CGGYuOIn`@E=si+Y4793jeO$CV8{fh&&&UZjcxnX~T-y}vYR`M&JUT)r zZ@@)o{jH|>gWB)!=JeUoN5>-(cO|v5a+FkN=io5Po9ei_TXzHKobKSo#YGc#fhN#oZ{o?)-MXw<|+I_tiC|Uh;+a}#mH09liZKCd>xlJRgd}ewzjrM^0okY z7;_uAldO8%=O_8PhS_mu+CMO$c<1UzX(lEKAyOJB7p#7ZyyFH*6{<^!tqx*n9Gh%cZY5Ic&Gc4{6AH9P;$HGBV&9nWllt@q2x5+)3ip z3y*;?l-t&(sF?%e1ZBQ7ljXU;QNYImy}iA_HsQGLobQZZ1Y&JME9I^tfT&hMo}VPd z(Eo`i20k(b5Y*Y(KPbJaaNTiYY$tg%-0|u>9+7Jo1H0ycqGYtp@b7UE<2$GTLfU$4_$xpC_BM|WyMSfqnfTdv(gBq2blGCRA6;p>3+7CZtgS;g zwQ@>AI)^2)V(-6x2V@2d0CLfm!VkRu6kWGSjs8K!Fl+c7KE5ocv*P!D|GTHo(Chw- z;<&hOZ<0s(VDTNh=YMFLm);Lr*PbyoE{g|cm@Zsg82!Ofle$kizWfDzl3&kbO@=Kw z%nc|MF6gWvOcj?B(nCVO{$0AR>M}L%zgIFje3$WTnJb(Z9yA*8sqX~f8B=%R*;$mq zJ*79%N&wxpu)I=!u=H1Wq70cN5Hk>nK^+?AXug6dEq1O)dU}!#Mvl2=!K1&2GssFl zz7^ztY^@sVC_2IfP*`ue{$*OaVt;nU-zDTA-l{oq3x0T)T zAlJ2$K7FRkWC`WLcWb86FaxkNJ#E9>h9WT8%LHWRF=7;b(`Bx2qWAgunzc|ICz%ae z%ujT5Y^X1CXKV2S8OF0kzE7QpENZ$)Qkml}*0%O`Ie@fVY6qwRn`nTWz8Ma10}t#{ zI_1nw1KtP4jJy_bj3s?^?fQ)3L(fF2Ym;}^0)LMKPY9o;@O)X5su9hbcb(#GcSKAK zR|fkf-HOA+iH(_{ z+Vm&Dgn8gJ8MpI#sxk1Hh6Xzu8{5bgvdOXfnRb;=K^OeG>jI8B^1-umcgfD3AU2)m zyD+~>wOb)BLh>kuMmVMXuEE8NRo72V)))Z6?%G8~JG;V)*#|b4Lndo%Gk;qdA78P~ z{a983Q0v#PEB;AYj3a;OUOCC@8(~eRVFn63V6zUU8gal@JUdBnf516m?7O<_0sQfk zem3miOG?hdir=ra2{=>+%?@3MKv-;|7C@g&}U*!LOHzUI13Q{^t5RJlLycQ7kpP6^=4R3^vp8mt2<@xL`P)hgaxzejF?4SxF4U(`WoizmneCjoO8m5N=?ZNRH++G+{rG*|CD*AQ=?AHs)+~MEC z8#f1Ya{42q{?A@Po(xq-3`O;Bu<39wq58|BVb$^_X#<>IM`#WE<&WpZi#<#W>uwr& zvW7`+8BlZnjNIsy;16OOUFnShk^vGvM&@?S-0%=l;Lyn~v3$LIg5bRX<#@0<6m0<- zfyVP_S5scP!5dLH&G2nb9OuiLp;IQTeULEX_D)%+06+wKW}UNYYV=jb_MR+Ya^y!# zut#Dqtjl+Kkw>r3<9Lv`D!tKW!{+`o?a@3jbUBAcqGB^UtQy47BjqwJ`B_w%6xBh# zLyS6#(50bcJ*D5j*jG@!n_soIO)TmheJH*^0n|jHR2)Jpj1&1+KC;E1qFQ_F!wd{aLYN_P$9DitWib zC@l&q@qTmi3oY!$<1jend>E}rA1-!nC} zoav$y>o>h5wiiGG;Btu8yCmLJvC|%FQDw&KtZGVyyG1lGj7g5;M2vyE4)|c-lG^v1 zQIJHG=0f@f0DS&3tZ6G!1W@`9@eML(r+_Vz)297(Nqt3bkoCmX?n3NV z#LoXJu1YUmG9Sd73%wy>zIgHC9ciPhtSHCpZv|t2=O4V|rxo znk8xRd^s;IzhpXt4O_GobCs-TuPNd5FE&@;7!lLst!0Wp#M#bjT_NLl9{1SwXcJv0 zj=83CMwj0H)+Lo*($6P8>xDij#olu|<#B)`2tf9fV>gJpfU+w3iCnBzNquFGBY9ps zu%<2h)NGKb8v-_mXEsRpHP;)$`iwVJL`#m!t{+TyZ6&N3zMxMcG;$-+Q1W&hOI8eLyEi|MZkeS zMhaM-u+NxKkSInMykutd5|9JpmXgq2IUkil9Z}=1SQlg6%`Tkt8P+533n#2?QKH|c*_8{yq;2}BK0593r=6LYU*Cm z=Pun;S}Ao?z?PCU)tXtw8&gX>Xdp0Z1eNRP3})>U}7&NPh?CCN3|RDW}ZBt3>xDs)mtc(I-0WFZ4t|! zsinkXt^2Ccw1380gqp~7{}870Y7$NLadXO1j%l4{=M54 zI!i!UCq=Sd@@;7pEc)KBqvx5pmSZ8+zARYY`go}|^@md2ZCY0NTu%LaHg5BfmEs?> z+L@n4R;ShaOyH$H+u}~6fwYH0IJ3UTHPjSLU&uBKu}VM!dqJ4!Ac8T=XB)&Ldiyux zTBQSwA-ScA*;4Q2gls2}jG2GL@MaV(JYGU-j#$9-J?~>>_vl{e=x|6@=5gv+)qJGi z%dBtm;#SD2UfdF$BQOn!Z-I8JFN34R9p*%Ks)r^SHVGO^Q<8mHb;%XYOufYwA4-+t zR=*|TU1S8_#^LK;SvpE&h}fLnhpT-Z0h3>jLodR>k>RDH5%%3R{fLO29KR?%;$vV-AY(PZr z{G6tY@xtB=fz&RkdPO!|9&hd(ihK30FcUw@p8!B=`bw%`{QaJ;##H#%A*`dBPvx7e z&Dbmko}Tkb*Kn_-e%48v5cCjbNDe4D8{HgOYwnwawNuR!K7bdUe+A)VETp;|`4D{)`n#tDH7bg`&c#rc!8IvFgf8(ix`g7&|3L8CjkFh3vr;p< z3D_0l9$~+q{h;hI&*|RzwMSEUIJ3}l%%r)t^@@LPl}#XMk#0V%X^hQbu2W5yO~|5?QdD;%>*-cg?hdIo#8af zh}r`aCBoG3CUsZUt)=I|JVMl!*uZ9nd+1FxH)3Z%^iYi@GARIsY=Vikvh0ong1zZIc z;;$FlwDJlzs_{_p#-}usURE_U_7NeJR?IH0qNcI#6owsxH6^T3XX*5sYW{HVZBT1f zDyV_GxPc04IUD?SjkAO&Y=M7m=PIa;bVOsIRfM$I?arEDDyjIg2T7jz>ssY5g)p?bO<~Q!g7E_}yutZqr?>2u zXGXmxU4}ynLp5;$gUaXknu<*wx>MWptKUfbi2jVE@50a|!v#ktli}W@%wKJCt&hs` zaMsQky6Z5mXF)Yj^R@;%Sy1 zw8RgaaO- zy`dME&?Sr6Nq9;@v+3+U(-sA4-P9WG&3(O&n!OvP>f2Z%V-bM?1S;MxHeGl|BQZ7j zlFGNzJd;GY@6|P)hZ{hX|II{;EVvZ#l>CIlOQ0Nrvuq^pm0zn&3QjAC)^g6?$fg%f zfnv;3H$Z56%ip4~$G0isDv2QyU#nCMA$vpXo zrA-xAA8Jb+Z9Z3cgTi;%6Bz|TkBE+Bsbhh7RaxzjwCM^k;?V^v8f01Ug$h;i$$;_( z_Hh!__Z0YgoXL-hq|w9t+x=3rvALA^&c2N<@mA9-fuN7EiijlZG%T}b*e&Wyvpw!q zcUO2u^Gm8hL+NOCQknD(j|IDDQG@&7zNIh1T?*JI(w_W~N7($KR7gR2c?)T}x%7!HtzrKCFEfnzCPa0|~wR$Uh7Bv;ES?C|b} zo`_Y;`$DX`UbL#a-T;{VlT5ZzhLj16=`ZcS%VbjiqzEzhHdF004s#@L=X+~mXo;oCrOa$Sr8QSg;ak`4u} z6TaHoarmKot2O8dQ$bEwMHr1=`6D^E>;U#5Z^!8SflU%H!35UglUzJ!e_7>JaovCY z{VX7=%*0lyZkvk)lw#7S*ZMq#hwKs83=?%Yg+SC$1ju{+;!w1SR@JZT) ztyVAwetPub7y8yfSrzlurfIdKA-w0$6k=N^XkQrm#YUyMx<)b|Uak{YHUdZ$3<{l8 z{iAusrl>GB=$CW(#Hva#K+w=8+&A7qAy~Ds?DUR3T7`Awxcf-w{hu%W53k20(9wOE zMjst8iE3c-2EwPqz;}4*>Nogmc!5MGLC+Z%MPl{jJ)GaG6G)k%jr6d_(?tzXv{+F5 zet%h&KY49yoWF6CG0wE+eVs$XftpCUj3ABgyP3{==+<<&iZ*ao5dG2NO;DcoOmUF?+PW?i)*M5b7F3_8>n z%o+D}f0*_12VB1QnX)lx0eooEKozv603v_S`&rb+d(5_73|*L~FMB?TQLtyLb7y0; zM&7_VmiGbpMN>TS0t^oCRH8xPE1MMTs28PHn#NJuS4BbTcO+!7u3 z3ZZxD^zv<-qz*TO*2laI`n0kiOp6IBx41ziwCKm+Svj<1leg6_d$zte8-8`mon=EF zU5RkbDkov?h1Db&u@S9sE5-FO3Dk7=W-~OgMK)2OE!#2&deY>@&hu8$SM^r#w;-*8 zG5Mu~%<#EVahyyTCZTt@P~bqhVrhEc`VRC}SosCyx9H%UYe}goMMeS>BEHg#FJX>I?W9&h za4~q`JS^2;OG&EulKFHWr#%JwfHL{|I9y#_BmP~u92n(j9LleRDi?ltwAyC0Ev-I_ z>vjrzh>0LLhL~yGr$bUrDQf0TgivcMFy^HL`(1hQ5Il25` zzKw1@%XL0yoXI^j}8-pz=jwSPT zA^52MOgzty-mrvT`(b>p>nN-EGQf`}U|^q*!{3p6h+_h(_svBlja}y6zN^ z~CAH}lf(mD%Q6`?p)(UdN!*1?h@OEa%iBT>@$V=jpS)Ci+y_~blJ z9EQGK@Qj1i|Cy7M*VeT0O6*Tmn+(AbL3!4>kvxc}A1-9oWS?Pnymf(s$}YyD&#bL9 z&AK>fjL-tR>_`>?M_>o5&(k@#wumwy$U?K7 z(~zFUJT*d@ zIP|S=AQ0pot4lAclyXo&`^c5i5OhKP>g%qW)vpiseqP!xTOWL?*@XA{3jL{DM8tvt zy}~_@U$Pp;GSYuH!8~O0r5R1mkOS4#ippLZb89|86t^6hS{XG%ok_=p3~iTHl*|}a zx;#@B9`p+|rY{YB!UW1;KM#hw^K^<_Qi1vfoe%rgPMYWym#cT>TOVG^VGb43o=o5{*3h`Oo-@0H8FJmw6MSs`_zX{{@ZvXi zx1`7@0(j>+-t$$23cpu7h3qoBu<3l@rSo}JN3>P8>8;BtS_)T5Zbi`ZjR<6^9~GDm zM^T50m(;U|eSUil^&!~?X5hS4H|%C6MS<^ON;3X&;itmw(d2AZgmJTdwD_C~z@=v| zQj=HaJ=( zbN1CBaPes3*lELsLlF)Jv?Mk{BtE|^Q3}4D{_r{AUKquZ=-NZtx?q>j2vy`pKKlwy zM_bs{ggM1Ylf6j(2cG-ikS{Q2j);K7zZ9USfF{#Nq{hB4&uO9dR~P0CMhZ*4;`WO7 zO(jT#(B8=Xfpjvd$*^ma_?f`IYzdMC+$PQgreqLANfQ2*J3G5D$Fb#|r;e4O;3f0s zl4#@8H=yr#r>kb-1Em8jZOT!h7YdqHUub3}N;o#zMruh1iL|_CwZ5)WkNfn@ivv`m zP|G6{ts*)iy{>A!?ntdU&N7aKTt)QBFdloXavpo8-_R!6;-L%QXa>LI)%XgW) zb@3;+gTxkwMm)i3Z$YI(Thv+UeXX<0 zOZ}oRn0%2Ws1bQ7I5e*-862d|;I^#gI+-DAMM~v-(HU9vQL1&Z`z1%I!xv+sisw%Y z^ull&G0uK#W)2kJ1UnRSstm4LQ$=?C8IZ0!uig=a?7~FWGeNj-Y^~!}&b1UPl)egt zSj#}C$}UTXQMm}6aL1>AhaKs!lvd7f-&q%&zEUsEIO3SLHN(dq`3_;>tXNi^Npzn8 zm$|zEG4Rl1=I5<5KuWkGisrr#;~2SLk$2=ZNAV@f;%WqH4Deu*~- zFaflxI0h*Z#hmk+IF^PlDN;%O?9d+KtG7d`rQd7;BRY6sqcyt834r2xWEg) zJkBP9^DI7?x}+NOcu2%KnL9`Z0=U!hUh%ABk$AJhzOn}PIlVa^7I{u4SdcK0rk2&Rx0KH_Iyo{H zkxLok^bFLjf=E*Lcj^egcQZESMa1>8G7wcNTbE|h#(WXt5Ud2WCH#pEEr1J97B{o; za#QO~p-~HFZ7_V3L~7}Vf&cTk?G0rDFVw9Je#Gm~P;SQEuBbF>DN%c#;@)QSyTOaT zwlyoy;G%XFKnYMjcD%&VS64DeBPn4ivajykplDmN^841qbb;rr%$1WFXsP<)TbQ$rEtqhIo`uCufkdz1;T@^Z%#Ujhx7}Tb$giisUuu^$c=ZeWG|q7q zZR~Miq{*@p1E;H-DXrKOLX#S$BYKPud5(yO9E#hIk;O-5>NU~mrjW8?(Rk)t7cX6! z$u=`Ua5g%%1YYWr{4pZ5U)Q7_u$geNNpf zF^53|>~A;J9{)B6SFIQ&p&!P-Fq!oeNM;cYW%E=#suo`(Q6sz~W<`6MbO3ovQc5qf z^UgR+sghfZo^~l6N*S?CW4AcLAOhGF?e-(QHiq4obAk2%i!vV9ngj>2B*+0QT9xUM zQc{IuE}U5M^?32VH^TmzGBgTC-Q()eBRrmI2$PCwOyM8ff}5Q=tU1II1ZLW8W{$>> z?nJkm0+QJnS<2x)>$t$}%6qlv@p~0nI$TuW59pBhYEk$~HdPRg7k)e+nnoi{Yby`1 z)K)J__1$qbk-2@M<~4Kf!`SH+uY`M|V^!ohE$X-i4Qg@Qz5IIfwJTcl+Kz}B1CW7nnXxX-4)Rpg&+}@FTOlt|P zv%)#=ptR=V$9N8aep`Kuh0a@Yq}^}^f_B?bs0~kZe9F1Q?dI+?Q19I|_$#0M%KFYq z66S=I^Mg2@9%Hjwhulms)|J3oQLx919BFN4jCPXR_z?ZxB`)4LlE|XdHmEY+Q`2Zy8F#mlOcg81Yv~2(i`f zNTR$|mTjrudF2x@r-wimLv(bijSD{yiC9F0QP_jK(BUSD5ktC+&k7n?N8q;Hle6r@ zOjf{K5p2RmR=f7pwx1a3?C)sN_rf06?5xveS31mu3ybPIyXw9QQxD@vpbZIN3VE{lTw1UVmu_! z*$BtEHxaqswzLvp>UGPcNNgbsSq1S-TREB*9i=Cm>~EIrh;XlUZ&pJ*6sioCCMzTF z`z6TBbEW%cm6LfeAan$pHMVy@UP+}%-I$F(^_EMM^wgb8R6BNyjx?^*@NI?Ii@x1H zdafuGB9im@Q{J0NUT!{dHD&@F=5yJkAamQtii(Ap*`gfz*0G8WIqVw-w;$&yB<=$k zqkhlxIqfk(Q@K)wsu`DHu1H=t*1N`~%H+*!dtRozIlQ*TSn_4_*+=C;q-JB!oyzEC zJ(_EeB*DR^hz0c2c%#eaEv{6~#NZo_SJ#oRP%KgO|&x+Sh?Ec(g zAk+c(Z79^;IaUJZrz^S$Mc(BH77lc|NB%Yw$f_*FUGtdBp%K_O)vv5j#UDnD?13`!`WfEWpcn8&&DFv8Z~)7R>O=C;NyVPiioJQ=nAp6~cG&%IbHX6dyeA_NrFDaL@k_B#N40P=X z*shYf>!Oxz+b+ltTg-(~Ua)Nq{|GIo)tf!e5_auF;X5M?ShIz*GU>Ngjd%I1d~dfFa}HF3>)iLsLZ9j7eFJ;_X{t(-}+sVY3-RUTY8A61D0Fn;b6+fVn56O^q_B`;v|H3Q z$z_%;K2vXK!Il)iOs{&+7MCne=%BVbrC@j-j*od+GOYw^n%xI?4dRaZ1s+j!3zY0| z1<5!w2*QUsb(e#-H^ugDtddbLr_%dWs)G8;#ypHTMP#AM{926clAE6>w0oRlD8zL3 zHV*|~)hX`gHTRr~s8%^8|N6BzifMh3?ubJz&T=4?@O3?SdbtECXc0qybdUJ?)Wupw zwR|n{aZiFQ$k*Tc3w(Rj75iLqAbVvw27sfmgNzbW8o(*eM_*(Kf?K+p(R>B~ak-u0 z%Ke$*&#L{LM z2*|+ZxS-$eQ2%Q~PONaui@FEEQiZBp{tPgU%=i@w)aPOV=jN!OTMPOtENAuUbPZ+^ zwATw72xV9UMwo=0P<)6w5V-Kmg0$qe>vsO=U^hRLo4_`)dy`1EPoaI z>MMjp}zT|^6PoBYCRxS#19FBw|j)Lg%7Wk^&_2kz4pB^y_r1)T}J-X}>`I33NF!6P1 zPQE3RTBEef;47E5d$&*&zUGUf*w&xvwNHo0D*|4T{mA%Lm8W$#S=Q+6nbVv+JU~MM zregfLjtfw?JW>aPqAn}g7yS~qPfB>^qHInitU$pU2pSr;w ztLVY{LeviZCn?P%8)I>U#90vl=Kp6%^#ykRL4UaSTZ5lMQ(q6O0dw6;z?r~Eh#V054i zV$IU`Myo5Wi^=E=Vz7DhvJ?9&1<*zKl=X@#y3YwOO$JvR+#Vw?iUfAW@G89+-6L|t zfzB8Aq9xU;OylF^pwCsGZt3}uGSgm@SJCT-R}19k=>E(Pge#W6J{38|wN|xhk(XeQJDP4T_C>Q?PKz(0DJ}cq;Vhd622H?T5k1 z8-kBMMmHtEaq2)5&>oOLz>PRO5kP33&YQCVav}dqw1!2`EYMCLhzylk7=T{M1AS>2 z8QSf)`lFzBD-jN{W_n~)yBmb6l_b^mggfkzV&R3?f8FEmqAg8)!mgTd*TlqRmTfO$ z`4SLfU+KHgoQlW1et|Eq$zT+*2?L!zS6Kihz3tV(yxz-YGa}01RDO;gnv$IgpDM!$ zk6X{;$rTVuq(To4`-AN0+bZEu58#|>Fd#>&Cq*ux247z&A*t6h!2OhHHm1L2`tC-F z4=X>F%;n94Fm+UXa-qJDHmV)MVKrTIYneDv|Tz!a;8%CBIjzW*K*;qy}Qy7FMI}|ySHm3=uJCC_OiXN5j3T^4ZMie z?u8JgIG%_8oQfJ6pH*7|P07engOfFkm3gKaVpHKTx)OQZSg+MNiFALYc|3ZQJS|1m zaehYx#hER!1&6^y*Pc&TE(x^KQU*Ul( zi;$u8d!H+6U}ql)N+f*POSIi&PJO6|PpxNL%r-(Jg9a_6`UaunlLh!6KqcErx&UUC zAa9nOW(>a6(rxr+JF20h_`zxzWi@k5BDzipKG&XYQ`Cjn2Rn?7F>N`e8tAQHltEv+usFO-6PVTV}B<@~z=*)5qUND1bsgdTc^2$e0D8h5a z0^#ekeUw$T-Gp2RsHsu2QORqOhtcMPadQS9lH0JQ{tTPDul!xL(k%DGX)3|+Kk-xb zq(-&su*;uUmYk(_?jYKBaW-vQ&c`jfLs=W>Tw=yO9*g1ym)i9`5Y#;LIksIpsc;s{ zDRn3$ncqg+ok;@`s#9zKVoCbLZ?@MJHM`zz)b-GEBYOs{@@WBkst(A%T$>+$(>E)(h;~zIJ0Qkp~yT@rJ2SrpW0B7*Ra;l-<(He?x>jhXMUheTMKGkPo}rG+?uy; zdc;|T6tm&v02WQC79ftJ@iVG$QdFa)0beFws}!=U+ozkAd1PI%PSh2S=O9IoWzCj8%*)aD z!RI&;uIE|#;G8J-lsn=MkQCgDkTYVNhX7Fzd%SsQ`6`;UbW^0^%NK zAs{0S8Q>VGbWEy3j{ajGGgIO&qpf6#=vgsXm zwxblQ$2N=1sldiAlngm~U4EwLe|UKCrp6f*bqyV?kd06>bFHjJg}`&zAR_cDO^c~Z zC3z}>^;TP^l^x_cy$RfpDw9S#M77d4LABXfaZHUk+kj1tso!0GLd?5g;UwYJe@mld zk9hO=e1I<23`mN&HYdChK7#hjl)wD3KVjAGC(?i= z#+lPVO;wW)$kk-ia$f@eMjB(LyjOv~s;3ix>MGpKz~u#Ep)5ARV}BC&l3MkD3XNTK z>i%p1Y$2P(>0ovSu8{SVU$z9OT<_?M$0d`;MlIvd<-X7;6;b`#41Xi9|EbaTzIKN8 zZ$}=CZ!i^Sa#hVvo27L$U>e*0(I3xotYFoz)y+Td`2?h|jGl4qO40o-z@}UJ(I29J zS~cKTV|o1e#({N!3pyLn4}@JQ(^O`96g}p`OZ^LF-hXw%7F_5b8dCbJ@s5+5`%^-~ zZ2=h<9J_<$FDux8d|(_2*xVKV>B@sv#u)pyWFostf60>kBT1TI{)Y%Vcx+4;xaj<$ zJ?B4u`yc=N{{qh8fRqHV1p^e$fS9@x-F5CnVrm|5bD?{{R{0EQI^Nyg1yu5bxS2P< zREz%OgBFJWONaevd(1um+DV32?Z0){ldZ@Oxsy0Jg|nR*7#IM$TrU8p)(}x9CmK_W ze=DX1g#5Brgl_u(uQ~Jg_)6a(d&Kf_xce5+JPa83oFgPC{Zhp9kC{_fe0&VpU*3dg zWn8vJ9A2N~-MJVf1M+F0Cx^oK?%liLfF2%r@ka=U_b2+Y=J6W;e{63o8FYl3keZ!Q zCmGncZ|9C12LOjaYQV4#)PC+HUkZN@gsacNR9Y_B3giE|%>SMf4>bf7VD@m>aa8{B}X0vM*qf2`hLsq}!&EtJc4rTVf0)2(X; zAJy#b9e_)gmqo;#=#q61=P@1=Sex?WfUB+T9IR(~PBH~fpOyGl2RN3ndP_g~0DSe& z-N13eU2)(f)2_wM+kM4dTHnr$>|b60@7SqQ%hO+`1GaH3dpA!1*Sh%sPkf+p@Z~=Y ze{)*?^2{TZYdLNt-Rb=zaiT?M9Qn2h1bE_RfB6#r{ku#nFhy7&i3p#{zkY(1aJt~a zu^%oes{7WD9})5KN=&{(*7t`_;I{Kt8ga}E{=?vo$2oE7L{U8LI1l^V`L`iWG`3yl z*Hh!)&%mT}7Kq@VqM{Um_IIFxSWxIOV$3D~r1{2ww}V$f{VNzwvi^#cf#?r7F#)H3 z#Kg!y4&X)}>GGcBwIp5zY(%49-B)1p&BEWid7=T0z6h9V#9v7*DfyJbUsOV2J9458 z>M_&Rz(yb`L7_~{$-Bn1c+dWO(0)Cx-rUy!FJqaM@Es2@GZo7vy1GTrR-i|FeL^;@ zrBN}G?TJ1w2i&E~s&aun$Gud2a0Pzku8FT8cxqL-6yA2&d|EWeaHL$p!}X77{Hw*T zp(0KEoc5pncYnE+jNf%#cKv%0pD-2LCaKy4Xz{W5R#km7!TC_G$Z@3Tr7)$`Ce?1U z6f^|o?lcvpX%LwfCe93X#UPy{30PRW$l&mIN&$YaLyr;jNS^68#5Sd__R6Jv>ayUI zcra`NG43z7U_RPgACJ{v9)n8NfN#fF{sl%?;c@i>8zMb4iqUH?`yl|kTB*CvW;fGv z+k~8pyFL-bR}&0!#MW50$64lIDN{CUI|G}J)`JaPw_oJs_`$QJAc(5o&hev+LE>_pP#v<2|Fb(s%Vf(0iYQ+$6^5E4G`y7bLFT8-oTmlCBFs%+!xZ<;8+@*Q|7avTNC(oyH6pp+PTp zf_40MxXvF);DId^aB=)OGo$#gc2%;FJlbjTEN3jtfKuY;YWdPS5%hyXGnwm%xZhU< zoT|_Wnd|V_Z_Qd?1>6>kw>PFv-~0oJTw_J@jPAN%Az6@EhSFT8ef{o%$!tfgeRH{2 z`?6Ls%8tQ71KovzV&n$3$_n6MVyv>EE z2ybzB(KfYuV|J0KD#G~r^<{^yWAnGRTmv)3utdo_n@7u-^B&g*Zq!W{kEj$`IHuo; zf8=&^^L4{J!yoxCle+v;*IDjD<)rKKzmR=-bv}Z7_|o?JGR3tg(&w(9{WvbGvW^Vl_+lyTR)Y=l%-1-FuO z@2ahc- ztVDOhC1{Km*!3iwqX+YX^l+WND66sZr}~~V!n-3aqsilAJun@F)$2@~o?cG9N=HiZ&{8VA3C2Mur0BL= zwbbsWV62pvw~!?w#x>Z}EWx_}hhiag?)Teffa__Vkd!|yQ&i8&kkf&mC3-BzhF=nW zz26|PTI(Y_>ZdFCGN1nHs3~N%F;cC4^-5Z<+{Tu_xM0TX20vzqxTYTc)%j#LdhpRQ z>+a9UuAd1Thtx%o^!K7>RrfHJP<~Chi@pj6@LXY3P`3kr#N`P1! z^Yz~MR#+0kmoLXXoWzu2!xPVMM$EJy6&0j_nGToxF8`RZAAt-i?=+Y~3KpaTsMVH% z-Vt!a;bkKKVTVX>bPAHlX+;K~T%Ey|TfvktP+VImK zIBrGo)MR?3YIrmI1H;7BqI#0+g@;B9&&1c#``VU$gu%EKqcAWF?IS~#%fYTMn;z_Z zD}6a@smXeOX69yAEa!7zB7Ojjr`SJ41}8@p{ZaOkzQ2P$jHaH7Aq@Q{!j`Yv4=w=} z5_B4-dyg{z*2r<>ZV(X>@qO^y|3q5;%pV&Qf#kYHC~ z1X`)oY*KUK{&}&}W%~L^md;SPh#r~Oa4sYYaDY}OC*fthwf4F!nzLJiO=4zF717S_ zYvy}j^h=$TgIU+7#~~jCUzjtsT-Tg!iMOeyFUkUQ4_&2_I@ojw1Y2Z>wsuLH*f27X zy)L+GHe0Hx9}XknUYn+T=@@P=)~|RImEg7*d!?BE(_qF@e)TB#)6}KX5`_ZUu)Bp8 zNCYIq)5k3}n@ptWC9IewCqg`iqj^m&^Re<^}tnwOX{YN!88G%^+abP>7DRs5@-P@^@~gZc-5}`W+BJRpxLGLz_35C z(_s|HAA3`2cfM*|MF%gFW*^%F-eQwVq-=$z5GAD~)hH!aPr;)^$6eG(b=M3W#`nzX zOb%vd_?Z|5LcirGR4d)#w0AP0w(S|RBTt$$?l~M=`^SJVF+U! zVZrYG31x?c??fD3L!Wj|?R>MpQBT9`82=$Oqe?nJ$C{qK3oI&k*+MM~?p74+I-$R@ zXFeNL+y$H3C6={jXW0mZ_Ss&^N3KNKP0JQ*k9lD+_IPo#Sj^?ihTY^81yw?r zPWEIv3&)PutZhLO*$#NH*E_+xzKpVE6)WS&pH&WB2$2{~eV7XAq4T%uTtUF*q@HT< zdC!D*Q7&-88W8_+boMG+aj>l)98e7kNrM`%N*eOla2*4wqfOS+$+i&Fagn z54XNK48|S==TZ^k(2v%8UwyC(dtl5s-6a(hpYdv$)QEk@lDQo2`rCYpDf;YYY*}DXE*!4Z5cO3b>^dToBplG)@iQOV`2^9U&dapx$$EmU zn@i5xE!&m%jhb|rX-M8NrpsUSC1WHuh0tXf&Ec7wDZqaDU(8pfwFZN39NhEY0^j@j z;Qw&;m0?x2+uDkXAX0*qbSot-jVK^3f^>H+x*I`2DQRgXmF^Bvq)WON(!J=0^*zgX z?|ppFIqz{@-#@)zGUroc+~XeiGsdWvQ2XsEH0vQs|Ed}9w%fbK6WFW6G9v)IZUv*a3^7)L7O*)s;y!MY?eD}ZV7_>b=6nR=gKIcSmWkO`E>iq@$5X=RG!N-^dPhAVxBvTsspfY2Y&@7Lke;l z(`0XpXPRypnpM`ZJ9y;r9ZK1OM&68&Ch)7uCd~0V&RO**Dt6}Bc@bTg$HU2CjyB%# z>Cu65DLhN1y@PB`>*$W?oC(Nvu`&GaeZBOUu9@z>70?FlySqsJgVVW8Br3!W=|C(KRCiwtk<;Mf)fAD07<(PEc5v`een2 zViGc(fSX zI4nOK%#<=rxX|7qqMlBQeC3E1P<-;|I_p7*MB~PWm6WvfovO*rZm{R1(Uq6@Q$2ds z?crW7lXZe;Q}{KDBl?G>y;H(-JT>L;@6MCJ;2OiPVWZ!#*j7LlGi$>Vs*gAaGH+*! zKK`;a!ADCv9yQdQ758xr7IR+?7(%a!)q0J640@)sW&uavZd5*-5VGwTlU`F4H@j= z0jp>B$JO)WXM7hQZ;C2LOHZGeaG=e{=O4Oo^(s0M5yG&!MPc6Kd6vT}B-Z*d?L*UE zxFQv#8RJP|gAR|)i~+B?TPPpYhv{wR;7tl|T6oRu9gl`ygntpd1oxtijBpTzVFVv8 z=_l}9oVR@Le>; zA0_cedT;;0mYo%Gf||hrq)tPT&Xc}fH#_ff&XmSGEmetQEJTRJb?P@n+%oq$ z{&+JJN}Mwe>598BM=c-2Y?TFvNxY52WeeM03mWZ@O{XBjtr*T%Ta6vrx_e%(#kca| z+NPI8c&!q7+HnBzYBYhEv0bc8jTBvbrOvc80d&nweZobud*?C!BO1y}*p4wfN?5KVDH z4HdgHlAtFkVH8m%6LU3WhK<5!Kb6aJq}z(EuWKSf6iw!p>YseCZK5yGJg*<{bJ7Hu zSohz?Y93@_6Jmp(s+zg^%^tv-;2*VY72&h=oH(M_Q1b5!Qhu?(_Qu413!F(mv5XD$3fh8nYb}Im2JOiy>4Zrjk|8e@cwUz{sbaKo+}*7{$e<7&j@ zKz5~S#JmVZKXxGG7}arWzCF|L<&+y7Z!Jj~@ZjN}5VJ2H=&eIN=sJ>;oNR^Frk`oHkMyv1jOEvt+$O%gg{Z zMb*J-`m9Gjyy_D@k!Dyj2$K2tMT~MD?oZt9a z(&5p`s@p)RF-Bbj|23)y9EWd($0*qC%ViVyW2XC_aV84=Ovs^s9h2B!N}>^!UM>ZT zzlJR+s^jD3QY@J%8vHgii`oxoBI4O18})&W#-;M=@cM^$FYg|Jt7-vZH~zTH@4kTU zle7W?nlF@;dKCE{;LLrG*NMzS)yA{0In}j~46XN4d#0KB`mujdI|f@LY3W*xX=;qH zS9tNHN}&c_6=t2#0#!|6z2}!K`+3aK&ZqOuo^C){1xh5;-*OK&f5~@k(Q1Cm+y_cDA`!2ffX6ZO?D5sw&5uDx=)?+{z;bE38Aj~u`83y$N5#cu z*G($@Y7um@*uju?Kl10}Yy9qqQwoLkyY{R7jVTQg+jXs$9xw0}X&??OBojjERO%ka~@e2NpCI8Q? z77h(cBCgmqs&cNt$xV8ir=eQBwMZ0j1PM#r>!6w*9VchBXfPTN*Pm?Hua6K7MMumG zF%_tY%NT}hI2yi%+*-UB1sw;qNoc?d4iM=JGb8uZZFDp9Pyo$#+#7(v=eG8vT4cIN zT|xPX0=Q$qOAw>sQc$pgr3l6O_>>vB5i%p-V0X8yl$_jM%uw6Kh1(oD*X}%&VE3LH zQzOCf`g2GGmer4+^<7#T8;FTOP2`<3-=E0jRAS`M+HhOWL~WD>`=;ef>3KD#h6zg;xSw6n8g6kyxCXiSUD0UHv!nun-my*5)} z+JejjkE9XFOY_kDd}e_D+UBWf0x}98`v2n{i{Dn~0~V-A+_JwqNJm5S1RUrtQ06in zOWP+9nQiYoe;qv1w;Www&INjUxHu8x{0XHZf>@_#;B#e@c;p5K2kH3u5=4Xf9XE*| zAoFNAJ}|K3r~Xe+BCVxG3i_Wd)N;xqvja%)1IiJk zh13!CQp4+8kb7S(jh=D9wtIt7z$bzDlt^T(&#Ww{m)hRl%>_!`qang3lvdiShWh8# zCB3BF8OY?$uUwV9C7Zw@URqWL+L;WKQuu)n?ndf^uP$Sl&D{jvL|t7y>fJj^*7%T6 zoZhC5&_6d}0NZK#*56$w+Om#?MBxAFMgG#S_?98^v!LE2G1|v0cC-N7!vhmXr1rcH zB^z5GGor09W7yB*uAVDM9m`5z(7|Yb-%(0lo*<&_iTQ0)U26$sT(qyljkj;#(u#=a zf~^2}7GOe-G&nhs*+6Ru?GmUm&l2|2xvm3Ek)e>^A1VFBM-)WQjf4a#%77C;$mKn}=3cKLYITHVG#!QX>oX1q^0yF9EP|!0jY-^@<|3 z3aO%?a~G)Siz?RA))w;1VC}JT(jYa!Ed)38KfUGc)`)wWF0@2QHNHe^sYjp#Bfux1 z;qIwMUHucc_G>5m0w5BJ`|9kU#TLICqGYOvPHV~?y}fZUG5BCk=c71oAvLGje@zaX zaGFBBPEqx=wH*QxOaMe63&yzqEMZ4CKPsn58xm1q{#J6PKC_^KRCw>KmTbVLGkx2{ zVH|Hc>VhL`vAAJy;oXL^R1u-BL7nD|4n6F={)ZJTA(A>GHBQ|iX*N*72gO5X^g=q(#88eR=`UC5Yt}KCTXd#=g;pHBVELg{Rr0s zUE)!twzhlJkZaaW`QIJ;vT4Avv$@|sDX&QIN7qW9KKk7jVs*NSijN$K!0qKt7@eWQ z4B2f^NG11=u`^=PalC+(I5HvOKFH}i(a^N`=&DoWg$@w?j2^{fNRo6WtWsQ~_PhmH z<|3QGee-B~3CcJ5WA#eH?9%E}M@@H2^PXY6#aGb1sPf-{G4(zKFV6b~f zSLfXXWe)p!;7%tjJTp#A#U=moavNr}7f!8IVOJ_Sg1^BUxwAwES*&(GkPZ&IDb`(G z9YzXm^lo>iV4a|qls_G}uG<@PtT_o@TC#TnKUZ&j*{D$Xto zYh)r=um%<4e+O1}&YqMXU9s5y*b{`pte$_roEh zI94RcpD@{)sBnwwuBnaY(*;#GeXOVMr-Xh8z?{6*GrvY8Tvytl{mM{MUlc2~n9=|z zfSY`JnT&?$Yv)@3(Le_5$)0Oi6PI1i-tvxxdxHVN)hX=2gC<>8^-@! zjrg}X?-L8S8^G>$>e$iVjsskfeN8gxRQnj^ewCN0>5Jl0k@_avXwrk0ttbMw)w zjX}l*60jNu!*SXJyWxC?J4O7iY{VX=eS-2%*Tq_hONg~8k{M)12u+jwuQhoq-sAiD zZR-wMj+_oH8@zgE>&z*LJ33l`=b?<=)bw7@7Ui4 zR$`#Z6z|Ma(-~iCtr)hks4tNaGU?x`WyLdMI>p!4OaGDXVL5(lXHQ+`_{#X9_q;+! zjNeUe?s!$JnfpDGeI=tp?i$%zcA`7{b&*IY)2?2(cmr_3dmcz)W=@Wby?trfHL6qL zhUYWq=KfMei&VElONn-@<7+&BmO~e7nz{_lzSaJm&Uzd*sg(l{xG7ftkb{2c2)JHZ z9LrnImuE=EaLB;JZxYTKlcg%pZ^6!P?GxcIj5IA+vq?HOzh$BV=>2EwuY) z{7qwFz^fMXhCYlQr+jRpGpv}Hxq&72$pR$T%(>9!6*4@b|4hkqVFCyvD@!MJ&f~VkElitg50)AN6;K{M(uMEdaXW zH}PNT3J@72b6%rLJ$0_w_wjc5@WhSKplRReWCYEmIC~d`sy_7*-Xdg1R;?+3;j*wisA_wk7=f18V&m=IoqOzK zZuMoqbfN)&m6CvKu(+f>V6|_Rr0q{I!8=VRs#n1Hu+y|#OGS^RQ@bszORga)sS9Kq zI9aV}+Nz3dY&2(NUtXgUZme%Wc+lSD(>$*SEX_Mz2ihC60XFdj&-(24HV^Ju!&nbO z^@3*2=MTl~>a?N^u1g0f6m@H|{kF5A0GrOrtH+Mx|~L|UqGuVrQM zv8KsIgTw+eP2Q72-1^x|fusP`fbu%{&GF)b=Um^u`CdzGcg<)CY*Wvx4f6ONVO|;IuMHwb z!&&9mI{j+kwwpA3n0sT?nWs#0C=TR~Q^W_BW+;qKvQwNXbnA-4lE+FO34Gs#vBcxT zF3gJt^Ko+=EhzIUH#j9sPOP%$eFMm{?)@o3=mpp^M`QmOu+v(KyON60A=f zrH2%_SNU5IswcSa%*RC2Vq;k)!$f2IB@wYP7g99c-vlXmPcjDyT}D^bOxe0R)GQzG zYeeIU3Gj3=LQ9}DbuxNp#34|dHR_%h^F7|!?g!Xz3wyDLMASXkO{36sD1^PWU51-I zI>w^Cnv?#y;?i#?QncVMXi&y0V@OL!Ck4zz84A_bc2Ak>+_Ou@~1{hR>g$ChaXk*88tQs!=4-_2~|fsT1MiR zVqzd=J|qwj7SLb7P?_HbyI@FSKXFY-QPgNPkgPOYFCL%Z&Biq2V-g0BP9d+6X$Rwu zQ?eyz4GqH`Iqk0LAk2R-oPV>e0A+xSAb{-xmZ}=i&^Kx-j|{;9{T#m%*Vd>(r`lNF zvQ-#&?m}EnPnN+q(ZxbNsJZQ4~S| z06O3zv)HGsd5Nhk_P)QBfC_7sOPw|qtBnwBL~&&ZN*u*WaqOZME1W&G!CMbPpy$VM)SyIb-9uCZ`goh|ft9e_* zy?YhW4tmIh$)KA|?G23-$2!^}OM1HMDz>frP#rbqIO1Y_~8ZU}g zl=5jJp!4Z7;$dAz(OXiB)WOm zwnpm(8_VOU`kjiZXpb>YV1$m&dIpFxB%u@*A7f$gq{hc|r( zW_M4KvQWs#2&rb37FDA9`d>c9=qbyM=`d=BEnMYab=VC&h;EsGlQ*4GWCQ~yD!dQv zqw&L$!byu=vnx+6q*0o&W9!w&NdIOke+Qrc`2pqO4K7B5y*M%x(EyVmv#~Gh@9l{} zmQBXc$k-U<1qI0?I045`A3SV{(Op-fqmfR_z{l1gx#9Df9p%qk$S)C}ajaH}$9lp# zwNxs@NYW^7?!Cj`k9$Pds?B3JlCjY`4&hh6$O*KxTGutI+~ zHvhYg!0|^>c^DAa)~|=gAgl4KE1rf%B7oDkLMQ0&@mdqI1SvM@q~jG58~(3T@ZXNm zhl%SvM14b5Bz+?(@3chmME)ydFrMIt!=!2xnV#;;1xcp1uF9LRzK#{}=TG$Y#k+nB z<65aj4*{py2lc_2_Y_e;YYlcb$nMa{f7t|Uh}hW^PMRI4xO-LiuOacJ!P&mCcheQW z(MkooNbV^sia3LdwZv$V@82`p+1d5p3K%Ol4zgmuw0RC?nt7@)#LkCAqwp&zC5*+O zmX&&weo|&O?R$9J98tcor36}99|);zwIqVMEisIi3#kFGrk8shgEx%nt z2PzXz&cSZ9kIM+U@)l7vu_yvIo23e@wT*;if@<)JIZN07_nq@McgxN?8)Lemlr0;H zP{_%#$R`3r847*xNb#S;^51sKZ~yfZ!nFl0cj>)B>MbfZmJS^q-6RkLh3as@T94w- z$K>jD1FbLUKsksGTFnFd0Z6|)goKjjp+rq=t4MXq^q`#$K=iEt58eXrUQy9wK zQXC;-#YKO)nC@=S_`4M*S&P)I=h*9Dz~H*3>Azu5>=v3cGQ=@uAY!T_)6#6>TZ2PF z0ARWejdmnMYJU;fN>jEBDu}R{n`6=nQ$3D~Zn!SCu|uZlM`qf4s$qpgEds_3!3eMzKnt#)~~F_OSQEmc!HODj)2%n<0ukUNQ>R} zSwhh02Q(DwPFiI2A)+zYlX1{Ka#dlGQDJzWXai4}C70KL9uVAm!Ljqk)HrIVN&ake za=IPG&QGXl-LZ58@3y}EHuj$#xhN*aBRZV9`aQPDO@R=!fZ&k}JkslmD({|bJ4eV7 z8KTNQ%~K#HL}o&5ujX7ABlR&5k&>6R)AToIOS7N08K^DKki#UGxpttLZU}cO?ppf zrgV-BkqS)d5pxMzj4qUW!wISw9s_?|4jFta8oXBT25t(xHS#a+&3lXknyDttqFd@B z^_gQzh%>h`##Xx^Jzj2{2M&9xXs}QNvGk;kLa6{ay@~XjNNk-S_z0V45-BW6` zs%v5%Iug_RX+|@9*-tX@<~f+S2Trp>(?u^B^bL_QM6Z5roNqvY{Bw8k>vswBP*-zc z1V1ooVU~H2^cUxxy?heSheWS;QL?-L`ZQsK@@~!IXH#I>Y$i3d5Srja-|L|m0>DSS zZ>;C`iY(9np2?7k=T)$^T7qt9)Z|sCdZf=s{^!kj1tnWlPQ);R;H+Q2s_Rvn4=M`m25&bDRLwC&(pyFcFIa?xrPKH_8!QRu0_`prm(ePjQsDdAjI8Q`p|LI! z%VLWDhzdunsNHQ@mwM6}Us_BI$n8sb{cv8^$YtCu#wnOrG0xuz`I}MsUyb)H^RFSA zhvLZ#D@8>qg$)qxfH3BOAWY?pSb2C|&ir&Gq|UYBP3%NN_TgvcoH3$5pX4tDh?T}# zdOxoa?S63YeHQyf1w>o|?d%q;S+*R7Al+%I6Kkhp6dKh=FU-QES{Q}3IoVnKk@wkT zWkHvqtlXxO34j4JVmjqT_B`J>v?clBKqjA)WK3b`j-cMfRC|BiQpRC9VwJ$R z?oqQbfMM*rluixq)97$5QKapM z3hpd8&|zIHWJ+dgj`kvQk=ciDTPs|zbrd-FsN_*aDLbXN!= zoa&+%i{Wg=#8+Vx%A+-LDrAQ-!YsS2t`!xj9kE!y#5qgOeV0^tgTL zF1lKqreV$&z!l1zG38f^ugYU4;Cg)iy| zh{^ciK~&vVqk=n`r|(dauC5j<;s3AwTe+Jc==K(IwFKNS3IRe^ob(4(=6_kL+|bzn zqj~UuV#4HK#}mPg{G|^BqjC?C_-j;auH#4qEMNE#v(w(yh4awkn;7r#dH3o?uX$PkM#3f5I5La9ouFT&F8kdR>c@!v6cC6e~FOb(b2sgAac6MHaSP) zStnIQ^!JyF7zAKIfIR11_dPb6v)v5)*_Y}{#O0|~rj39Q{6RwBUL*#vy@v$q1m@>TJD=t#set|F(&y9ZxXf5DElGw;R6`Y7Lcw96< zwg1D){5Gau(#qY-37*`{U2MqmKw^uaopYkRetlKF!X%`ntuD*%Tc%Go-ms$z zP<8B`(6X@ffZHial^gF^TH%;$9^aEzKGSnxA(JZfExTR`fzqw>T15}VT;GGMk)_ak z|E5gXL!olsV2-I+uau7B)ma;r2_0U4+Jw~1=6(qbn>1dpOc`izM~&1odL6td^&f$N zqR>|a<>s!hQaD2`E`GJsuw_?U8j8dpPN&z4{r;~hAL><7y4l;+1*pb5czA#s?*;R4 zL!zZqg2w)JJ`T5&j2#j+p#0SC6qi08l97p7$UIhCb8l(1_&3{TB!NbDkjs7Jg_;_z ze2p1y5p5VUtEK$ngI->wmfoQAj_X{eRK|kzmbL(I6^Kq6bO2}Z{7}2@t0i;K|DCLM6#Oe$9pzgBST{9>&>y7VQeg1=RSk!A zd=$2IbhCE%GMxBKJZ~daGwK#P5&Kn8jAQNrGZ&9b$EWDhg*X7(%PpC$xQsjT|CI_T zs|yFF<%isgw1vUQN3$iOz zbIxrY$7LE_#y7c~x`VlQ{DE8-$l4LLNyM&d_4c6YYgeSH+C)d%u*KHfs1irwBp$s& z%A3{F&PF+S@Wkr3nLMkb*J;BP6cGX9y2zLqqXmgz2XD#%ryJaqb0_1Liy68+?e&W{ zO6>=+?hmaH(*GIAUcF9AJIj+xyAc~lnW8}}1FJm9f(nO)T?u}AGtBnr`EMHMHD$^c zYt$uVNIB6j_y3bsRb&7f(#5arSjc<~4&(jV--*DXlmQ~T`)0_aK{~`dV@Q^trlsI+&kvTuz&=GS-hJe0;5+@2+_5@sN z78Ve`65K*cNJEK}^t;TtWyv^m6sb@AfTBS{11=H*!W;*!S;+6t=M=zqb|xIO>;DY_ zm8nLDBR7*^X#WHI+)mz^Zxuu0P$7bcmeBu_ICH9oh9iR>eMLVbHk_D5@C!FJ7Sg3dMQJMI+T-MY@9)mqynWx`=tv6Etc;-6up0(JB1~jstmFv?r$*;h zp}NtrlV2&`+3S9<$X@R*)ejGRRDbJe9k~`j#f}P&)rXN=E6^J6CWOKtm}tAYX+$Jy zRDP3I&(Qm_?t0n2d-=PY>6B zWW8v6v($RJbO!3pGwJ#WXsQ&cGiX*pqRWTy5#bNtdH*#ds2Bg}L{Q~RyK&?59|!%_ zIZt&pjZHh%bBe3dY!qG?Ni-3sUOG>jqM?vhU8es?`NsdG{uGy!Jcd zcNck~GIcy2U8@Wfnv=DvCO-S?94-@iyCEQZp^qJ`RrayoeX@`w&Xi#$$LV(=q)`P+WZ?>*8JwKk)kJ=g)=%v`;iHd7(^<1=>6oi_ zlYVq{SkvG=o_w40%@K)kj+t-fM%@B-1JI8L9#Qgy$sV=1YIUlgzvUMm5nZZPYGt45 zviA+1^aFYRx|bD zCm|L{dkl2u#;)mp2dnzj#QT*)1ovFDd zqcjWslijKVj?+!u9z$(Uz1rj-DcBOq7*?TV3)MTEi<>8TJvu&47k;Haab@1RCoAz4 z>2S$JiG2v(=L8;b#3*xtC4F)Y0kvsB(H0%f`~lzPeE~(R^@^q%C?ta-hFju8bBQDw zeNM8ia#qCMFfwl*;Yh*DosOk%;{)N)508avtoyTCDK0UkCu!*?O}*j%f+rhXb+Dtb z#*S*Y=*`7#;)`$d-y)j0s(wI@j3%nh%ci(CbUakO(8da6ZhG)}E(M*4bOpRo`kExe zY-(!U{w`UjWqxODo$HHXzf)CG7bpjlOX@k>cvw5Z#W}wjVFW5~3^+io=eo=k(=97@ z*0Y~7z^#u>Mo3Q#SM57GW#cbugHQzu)a!Jt?{T+Iy?~VoH3UfuxQI{k65BkgKWole zT52PPhJdV`m~+G7l0c6hBc$H&xFXiumejtOk;Uv`WTScxcC}68RwrW$9e+^D-ZvDt zjSj87S(58nHWR}NGO;1OFv1i(mDx|R7dksb4ugx6uqEk1`mlvV%_5$@56zsXfiA`j z)4CB3ef|;mZ1~yohPF-{l$wIpjJ$kUVOQGr`O05lcRz5S%7_qr$~C)@_I|&|ay@Lp z=V0YQyq4{f$d9m3$MV`}OSbo@>ie3zXka8vJ_XF) z{*2W^1LpxZB_%Af3kc9xVB4p4^{8UEYj?j|tg5RwwQa7V(+kb>HWqqwxirnz4{io| zRh+mGuUlp*!2B0OmBJ?nKaRG0FJ97&C$%ipYFanxjub)74z;0m14qTuNe|9ko|w1&_=3vxQ1IC1?LcK!BU^0cj0MG` zS}0u^vc|62IxwEK%* zBEvAb2$5J*jo~<`V$~*dRI>TrVh3AXoZG0jgHha+hlR&Z%W!Y#Cu8Tv(ActgNYs{# z7kTOTICe>?Qrv~-6APVglUlJ$2kotAXEBxPSrfV`buZ-I&IKIO&g3oGMh`j)hc2zO zyimG$t>R6aP6q|`ibgOO`bRMHHfIN$&SVG*CM?Kdrx~STqCNdZIVQY5j7+?DZ!QY% zzcl8joBgPNl-^i*!G8B#RK6{9_0)rCoPz6K%UZ>HX!}V*sq-|d zL-kJUwZo6ROYgDsU$ub(B-mj-8eBLniJfP(o2lnlA!L*8UdtB>3yY)B3WBbl+c>0X zAF&GxL@_T=1~6jJ0=ieUDd@`GPrJLz78qNV=y8j4%p9Q^tjmV{ypdSBFx5;w@e-g9) ze6EZwV$)Rfp?=FuyZL_IUc&SG_H)`HVQqo2$6DO|1=1<$JR*XOHk2bt-lv@NA3XvC zud~Hg*_4l{9(ss_LPsn+JDd46bhV$bOS!w=&6qZXDZ~XT+@vTjI_W5Yh26#@Va69^ z;p}WTTf$BWUz^T*Ds9&jkTL$!v9wVn2+llHVweN;5}oI@gWfAcM`JVgb9R!6dy5xJ z6LtrKwiCKu)mb+0S2Jxw*Y7QG3#}4?ZiZyz<>n#D7S|2AtQV3$hH`+J}kpr?d!&ZzOv71u_q(>d;!l;MYo z2Jd=DOyZGU2x&J-juxr*wHr8vUN|)Iz*!Bw3R=LOb+@L`tqyL(w72Mw7EJ>$-VLmbC*Y!aW0 z71&T@cIV|Z&MMKVPV2j*Ewqz|z5Vy>JG-Cid+FYS6E}Wm#5{`MIVvzgE2YN_AEe~7 zEcH%f!1;RTGg*I1Q3$Lv!6YwvfC%! zn^JO)ss}NOP@k62*Y;mXMGb#@Yeu z4p28Y7-aGfbNxKMIsfe_HibQ%N2q_gG)vT)*skfKZ8?iDmF3JCrezR3sFO@}x~;+> zcTtemIHEjXA`Iba_4(Fc*Q38eadL_pe5oij7uTGH1yQ*4#S(e%gsrwbbZ~TU@#a^N zSes2kaE|Vyd>gd0xIU1_Il~KkJk4;-uhN!;uOgCuq7hH-C_Y${-gcRDSzTlXe^9Co z@pgT#11|_-2E{L;npJg_XO_528%v=~)HlRpMijjaUqbaZ2R^6VuHQHx;0YNk^s^u- z&K@jIx+&$5p`~Q5*S(S^ zVtTk=h#1!NoC@j6Xp=iVEz)3*@mXt#+HFi5sT2*K4SMJPQzB(dqIbOLb-B4lvc606 zTbAAAosQ$W(3@o=`?JJk3u`o``QP7rPrt-}x34KuD&l8@xs+Kbw>aD-)7JuOrPD2T zkNR-nP>(z>7ChmWgf6pcEoeU4D(SSa}l0PX*!x~cfUdge>zLw)~;5SN5 zBYwKZy`CjCk2+A{5M(cslDphL&wMhkFdtoUV<25!$-JVfuQwBSif#HZDZ!zem&)C7 z-N-x2wPQfUxLF~@sBY)8T3V!hQHUb1&NZdZ#2NUCgWJ#8s%|;fO9c@(_uaiEPj&3c z!v*Y>Sz)uyZ$FO0d6Q0cZQ~-n9TNF`MphY~!Jf!?ztB*PBLqc@KD~*X>{p<>=_8hv zYx4q>aEaZqwJFKhs*n)0uHxb?lsU2{3*!yEvtLdXJ@c*U@-pb;&E~dpOzlV1nUx$a ztyUkEH&_?6PR%2brF+dJ!KJzptcMJ|`x6??R6lLRHabSb;%I-|X5=R*;{9=ZZBxj-eKhmX%P-Px{^+|*m`BaW$PTK><8tY;cRO$k!Ry+M2C-(X*cS_Fjc=S6 zetu7*uW00Pyt%$k*A;I)8jL0Ue0%g2>iP<(y(lq`Cr79;k(s7^sz1}$nlqys5?$R^mfBNR4Vtq8kTUs|K`s^^0D}&kJyI})fJ4R+(ngUIJVhWBCCXCAN8+1%=V=6qBD!1xzHtyn%iN8lw`#Wo`ghhF zT-P_T-{UXF(v{Xf*!9wFx`a`j1=Mtr#%gY)MR*~s z+T^WqoPAiT<8pD5eUQsbUKwc+7i)G^p2Nw6V!sm z_+lo?!pL_b`ZI?JMdw)~;i?Cg2!*tF6yvdnsuSF^A3DF!e_`ec8%i5KeLgqEslZ`_ zxo-NA^=Ylj&m#q6Z(+5zvR=i=w5p%WdENGI*ovJ3Dlc2J4O1ZJYul&HU!9v+#3RCd9ge z;>65LX76xS2Z-8^;#`&Xd-0*%%x?6>)buNXlP&mGDz7QSUN2MKz0w7~v$M@^0f*(@ z6w@s&p(D~Vo}A)N>{6UVPyjopRQ$kBv95WUu7b?;y?5}ajo$ljZe9Je|tDw4oWpE%U5 z*nH#>XfdgC%Vv`jiaN3*4I!3WYar_KIfx)}Ka#)5|DOJx-7D=NI0i%47Y@kc!5ghaWp;V6MUjELOUGC7Ud38T|FzP zEEq`T|5l~Gw%N6Q=0RI&J`=o{yW1>iHzm4BbD!4?NNQ{DhpGi{=%XcHWoL_~#KZcpZXMx|j~(WmbxEV6#L8Qx;xtX{d}_1K zEg>$1!>`whI#BXD!|dO3=VEXXP<5=2Hj1ob^Ghn{!y@!O;D~hFnrr zxF$qkc(Ai;Sh`}-Tm@Hb@k3|4>D+tiqiPPVd1?#z-B@ z6{kW9fm%CFwz~yv@$z1_Qx^Jx!Ypr1biK~J-f7-^gU=X8^a$emvw`ia7h42&U)yH# z-~pCMnoH|L&||jEUK+QCtY)SE`u-ja%=nxFFx%!%2Bo|AG7*-8833no8p*OC{YJA$w zi43%zRaNNgb@-XJ!BC!LRq^@k>U^0zp%MCrD9g~}@z-_f+=jNkOsH!7G9ZciZ~5 zEvNiUow@PJVs!dJBFy{Lsrvp>WW2~R$F$)I5md}U_Vl)NMm}r(gvF1iFcosfR9BiA zHVu(CRTvmOGraOsePc@}BJk6??Fa^_T(W$94PBE>@k+k_p7GN2nAHSkXwJ2rwA7=Y zsv_t|^<2W9czc^4i0^&X!00B;wzLw6x09@gB~kdqPW8WE50RhS0aH1!_ImMg@>%w+_s3nlJ0nTu3oU+ zxtV3^H+~xUlKN%CUonz4!W2MAG z*#mXVr3);6R!rAi!}Pm2^oO$c80mi0oQBrR6)d|ch2hZc=)U_Wnfs%kqnY3_OITvd zF-y}&0@ODqAvq$nH&Bzd%Pkito-|T*VXi!wqLNIFq0b*yf6f3!y<+vHZ*F(eoxlI` zw5#x3a$^CS#4oY7kmk80{&V#cT1NARfBIyk;AaV3vC#y$K80$7KmNSP=_4(UrChE@ zk#f=eDn6l?%Zp;)WwM&5tlH#8*M!!*mO8F_!0@^Fm`emz`dl*BiyD3|4YV|QC$;Y% z#U(-BqvCJ8uRLVt$oYJgDFMCjt*pf)ZDenX+ssO)StMo-^qvil>Z2Avx;H{HGo4ZC zHjl~HM67luxxU0xTU@xbO=Hu(P8AIIpQmiM7P$QA7{*6&<1KZBjb8WF(GO8iuW`KCeh{V6^|mkusldUv8p36gw1KK(C4?`iVPsJbd#s3a&{}b(r;#u1Z!tGHpz$ubwuG+k;gz z=k%z^UGZ9{&fDEVR7G6-O^&zkgs~=za=aNI9O2u{9LZi32U00arkCc?tOZTN>e)gY z<|cTK$|-U&j14rRjtZHzgbw__tIBv;9_5)@F53Q}mDZ`>^x~2GklV=9v8QXjY-I@z zi;2xjPM5mLmgxCTEWT*({KQ_mvQq}Aj+~{``*jBgtjFjp?@eIMXlP^#ey&xN&Z1|) z7NM0xS#?oV-&=Q5#jxK|;S#m6n^3v9JIsqMyc--)2X*5B(FTD zx4lxmoakd*WBr6ALyCJdEyU;m?lPmFXSM zmX~rK!rBX$#89h*OxWVS1FPKD!@Hh)Pza8ShWF=zSn);OO4f4WSbVe28k!o~IH(Ks z$TnA`K~r4rYZ}R2>C8`YcZZkPl15%Eo6Psyq!kV42p^@}W$87k8J`q)NHobdS>8|b zyu2^I**m)|jhc+-SHP>qanQV_Bfo=~ZOV*hA2SF2hz59MQPpU9tGN0YltT z&+2CT>6?Qi7W-J1x=Xip9xp`!Rhh zzZCR&zx%3NKTNIPWxOnVmbjp^y)7_sxs```Yp;8XLGCd7+7{Gry*rv&zWPbl^u089 zk@LfP$*&B$-kSU-0+K}{K4Ufol@|s+eg5evZRMCk-)4L~CRp!77B%$RbN!{8$^<60 zPmLbIw&E&J?oP6hle=w3+qPh`&|mf)Ux@weW8yVtlWJOj8PHFADX}bjnw%{j%iZu8c)uWm_fRyop>*`GvdUPoR=p0#~rsKrllE=n2@h`H0{ zXW2*Q?PU^D8l(MbTYPR;IS8V}mhxVkLy- zwc=P4q{&rH=z)&w`1#kiuPZlaWP?%#_D%H*lqjBcG6;tb@R=luM^pQSi=0oi>30}z z9X_7e5GjY=lKLTeGb^TKusX-SX3g`E%-Z$v+vB&?z;yZ;d!oKkINA#;rBvYPBx|4 zG|lHTzQ)o(8B-=CUDGd9pP30~?c6N(-BUYqrxhJY4C=s}WFNMsQ};*CE$XYG^mWVvL^Bj2Mhe@OXvW~3_x=6OdEb9`4rgbF^Zh)}C!Xgy zO#`>|ARDdftr9wb&|VPaz)0em9OSH1Fx}YrjlW8UoKv$_YTD8r^5*VxH4+NhQ49HG z7FGC(4>&x41vcmkJ4MTWjLA>2tgrP^7Y5QRA13Z=B~Z8Ta!MVRO8#3c`;`*~T|GHN z9e8JN1|WmpC#=vbovC#Tsriz6%in$_?iXKr-0c-*J=ZS})m|$Ouxd`IYu}a@0lxp~ zLaJHQW`B5tCx4h{kUXrZbdouC%ReFbXgnt>SHt%MzGY(6Z_4$qX@Zy;#p&wQT5Y%d zKkwc`FVezqJx%IdJ8_r%5V&e*Qe-I>JQTlb8O6W2tuEjTX2*HQ%IGRNt4pWYIS{cBiX_ZeGf?hMf2L ztKEp1oVA8iW^&KC${Q1X7-8b~k+u2TdzF~;$3dt57ILgiAD#%QR|i-abN4cqC_;Vz zwwe>oa+)Q5F=km))Rg?iU%-LknZ^VLeyv9uJ2_no`KS?b9c6gw2x-CEm!IE`c6&GZ z%nH~6!=@n@eqC^Q;4QYznaw3j5@89rS^>eLlCu|wJHb^>O+u)3k(<=tc#eFk0BF zcoR_I^GAX6z=E@q?f3P^km~tX+a@0q`t|YyFY-j8#c-fOs?l{JTvvRg$)up=qOY^4 zuT*b(jsXK9=wH5Eku#p;TeqrJ=K37R_#s&kA4E)6o3-xX91soa57fRGuROIZ_ zu8o6bEci!Tg`H)(&9@tqjhiOGwD$dX*E{($g9`WE$e-SW#O-^Yj}(yt5en2laF4cg zWz5RL62T1^Hzsw(gI9H)xcNSEW(gbb22sMoM#RSxhXy-1r6EYpDB!Gm=6-}kE- zc}7Brr_w2YTPmyQmN%C*xAh|E_$F$IEQ7bk<~lRX43&)2&~^U(J1w`7iCE?l+$-NH zJ{SvgOhJ1l;Ap7o&EYsPMzBoW#oGc`B&p1~P!rHR>1jf}1^kd7K+jO1v&nW4{Eh>d z#-n#Hck~a@tu-T9X*Pgw0NG4CMK2r(=F1kc(h6rQP^Kp+xb1K4U>29JWAml@!DUzJ zISriOu4KS1kxHpLO6xyPV*`+UhlmF@O@SvLOagxk6N@(m+OLZrRNHtr5vyF;Cg%G| zr8Sl=W61=~IpC&xf~yh(CvmPZ$XM@UDsyPwC{QQquJZS7Y*ilwqX`P!GTEn$P8vJu zWy}#oI^(YaT$@?N-81^rsL!@3=sZprx?(p7_>~~TCuS`+Im|oJka|S3B zgrMAJci+n}uR}e8F{52`KJ@gPp5>dJ9^W zl7iiAn895$GHrcF;-hv_c>={HJE5=Xs zWQ9bF9{e6ze#-`8W&pwxpXc6Q&k3cz}!PjoKlCsk_TY)4J`AKr)vrx?9U zmxKdRZ7w*c?LK_kn0>`hh`Clqyph!d#tG;F(WF4Sdj8-9H_P7ua`RuC4TJfx+NAnU z%IfaS!wZher9UUuHx8$YQ&9fo%22LIns@_qaWk`nOcvwL{$m{6y3<2+lT~L@%j4xd zf4|*<$|x7M8<<9sJaa1et4KoG ze0r{e3zA$#oVCeILiQPAjEV+AG5Sef4)aDv_ z)TME2se5Qs*)!{tBoDSMj*LB0C)4#WUNT@{{z|JI6Sppg0{b~+r+1>oKY`(z@k$#F zT+25J6*x6cJWr-G=j|PLUbTz=*7K;?=o7czO;v+2R=t$P4-fvZL!G~dnK5Uip4MNV zuI8ckzDOR0@~BX{I0 z4es|@(-*@XXXKlMiM4$B?JtGfo18w*svNRwD}T%-JM^W2JVt0ep27<*r}`}9?A&MD z!3V2z_~{!a>B}c_gkS%Mc%NICS_MVvXrDS}tGw6zOTqzdE(s{{OSYVI88gbG$@zHb zh8mwUksEvdCWlFn)iJRv;`f(z1d#Pka(wuVpM3JFslyHaw_Ha!zo|2>pPzq#yDkXc zl%J$qS`BbB-(U_nv0)JXY(8<%@QId4jefOlh0`if@@de#({j;o5hC$1{lxP(fm-iz zxxqfp1xCnlt#EA?j(hy~66p&*auFHDi!yyQ%-9XL%&Q%CuL{*ej=Q|@ZTX}{-NDrG zl#XGcZ^a#akfRyitm z;Ud)n9N{x5j3miofr4+SqtY#9tA_+*=H!=ym=afJIO-i7WfbKu5jV;@C zdz@PEyD+Gp;`)5NYTHe9T2Yu+QuId6%xR8Aox|>OFwQsn)S5I(U#MLuu^pQCb<#z^ zt)~eduzn*_Po@~vEXrH@CBvD|pmNY>xTvA!=TW+A&4fp0rkA#cT7D2$_sH8ar0vREgd0zM&Lp+I7ESK`wuhT(&n z3r0T!c1tj!2OSc`HcrBT!Qsh#P2S=o3#B-n#sh9duVp|t7OsPfj=)z6@N^%hG!lh@ z@^{r4$j1BTn{7?L6XlCo4WEcL`h$!o&Ei1ti`ToRN_!`kojRnCs}=>m2+J(AQJSWh z@sm`GY3IEttrP7ez37Xw76T4v9j1xNY^AP`8 zaFZKT0sKE*myxP)G9M7>6*fYL-3_4{#w?8oo$zvsNeL$ZBitzTr)+_DJT#H zTG~H02_BHLDhrB}$Vyy&0`Z}QcRn(87GJhB$)~ZVwvieY?Q66yI5_p|t5}~k8}qGB zXLJo>o(|xZQ{$b2l&jm5rw#v#k%5`&vK1Ey@&s}(ZtpX zoeokzCd`7h=dg7fTKw?i z>vEdNU_7|$Xn64ym?p|Nt+ua+y#sx4pynBsyyfXz(`WL;D@f8*a6ZEp2oZ7DQ>J3zo?l|3+M>I)WAzWNXk7E2|M+QqXM#ChLzqeE zv6$GRnVgwkY|mfe5 zWLm*3*07@+-SntG{MPmRxUMRM$vssM>||)!i!;gk@>oI)d&fCC>V0UL+eWpfmt%Ti z-~*4n9+iZ%`$SH#o$9FSs1l-`C#%2PvjvyScC(HtE-VZo?w`xJ-ShQAK@vA0v9!)~ zi*frV+r<-CHYPgn>04K#Z7S)ButNT|IO7s(8K8P{d`eX8T*L&%U8@9ifYJ|$fT zk;N8XTb9VLisfgZTbV`LRjThCEBsDIx}>zqRYf3K?noLB3UoG-S%uHc_br4n(o&_y zLg20|oRD7fPcYAY-%~oc`L#`0b>(QZr|)63DY*Hm`Nd4PTR2*OelMfN_%TZ0Y2w?@ z1Hq7Ir1RqM&tJvj8LnKWdHJ{J{aBapg@uK+wYAC-cm4lG7?i7M=`@xyYy*V33M|t% zvp1n#yBe+N^qYoA$?TEhiH{V;YG}`F&p{yG1^Nll~Ni@?f$Ug)0na96xG#E2<25$J-)@OkVtd~b7 zrd(DAoqmqGjI5u{+~7#K-hlNfUtfJm2=2>$?MtjZk?C*tYABEA2~FgZloR5F-N(dd zrIBzAo-myZTk7(F**sxgr)a4~fMfbSZIEe>|?ZCI=Ue+1t$!#-e)zdRL`R&c==c}Cd8VaW6(a`uMqOxL!t4$(xBnPq<4^^d2 z`QTnz57)x+daz|ug%!2l-3#taeHy=55j)?d@-^!R->=0{bsWzwF}K;Awt1ANxvZF2 zUv5i1ck%YI9wximuqeH5c4N=HE=zF>>Jn>|;0;Vxxs^wD)^`rGOa7rY_>1w5kwez~ zz8>>Tl&5qI@_Lmm<&Chhj(-mZ3Q9UT%OCk#NjDFGKnu9`E%)^VZ_8lc!tyguxsg+Q zN8J$I`J;o@wi^6mF{co1OH!c8!6-d*){H;m0DnH4 zO?Gd@CuCGrzQRxzVHq-73J{*@u@DKCrv6k0#H|S*X{Sufhi*>YLh_S7o(DyjKf>$+ zVhZoNEsxxI$`a`5#plNfYs2UI?#fN0PWSHmxuJK;vl^L7%`*99eyW>2f}VxQgp2zfqs z?as=RUhEe$^73K&X-&c3PCl4v)1#r_Dyq@a1ghIMIYJa6a@W^No(H8BPz6-bDyScy zGbLP{!Bb*&_ zjxkS%zKd#3_-1U&BnGlDOE;Sa-40b7GNoYX%Rb|Z8u$QH=e`$ z<3_FsE`=1*{`lWr0BNRy%~L-j!}iP<;1U`Kg?=N6MvzgTgV8WUvw`E!Yx;GaPl>ec zPBwsvXHNv*gV< zMS;l)nm$-S^0}0#>@!|}VBP*a)3(fn}IVV)q+8(&za?}g5 ztmF!3f}D2k(WwfX%{|ImU-$TIwfN2bluqXfPbo8^x5?G>7n^zJBCE&YUe}tW>m3LF zLazp^bn~zlu(Zq0M*cj>%PmD|47k8A0~r^=c5DC)BSlJA6<5(EORs zv3cXdW5QC1yRgm*`KFVg=$mj=9^z+ydJDn2D-|xvXJ=_YUwZ4jAAQm&@lRc;{y585 zgrVoOz!NI3o`0@&M6{q2sXcop7{Ix=XR=BK`?YW6HZUpn%8hoTv)vz^F^L# zOj|?1;I<~UJVtu>z0b$L0KJk3~d_hSjd4`zGk4UljG=37m#C^7x z&WwSv=iLuyL8f!Vg)5tRc4vPug0~_g-gH&U5)i8JVaSb{SX_l8pC#^=gca;cBL zUiynq<}wN`-mp>m^zUE)IPNymQ)`3xFIM8j&5yT*XQ5`@q7|PcfJOst&1#StH(nq4 zfm1y=IA23dkfl({agtGI@$>`aBCK{z9gciL?$ofOoz&P!sg4KFuIx$Zm3eLR>vIOq zL%YkeC9E>)_wsIjL_EU(GdI|JD0WRyM%L+aP-h>hCPR4blJIw8g;_J3rC(PZ zKksY*t4#9Z6?8T9Hn{lUjwE4K(z0;-U*YKJ+*#Q5flc5U7qVh7TU~B8JEFnNz<*~T zPcP}L$-#uycx{TXNB-oGdEbS6-Cfu{Q^5JFa{2AJ4IRND{^ormBI8Iw5&$a_h|{$_ zKaq5vpJlvntNSiQazcd|(8Ct&P$*jvz9A|@C{DazH9t2!n5fIVL9GUX<+-F`#)-3+ znc_BBT0^EMB|1O@MzKIKaIO+t2X-NhB~{rG;4RAYHs=swR7xld8s*9bWgPUOXP+pO zSRWZ#C459n!|*n{#>+;SRLrSd4)=8kbd~k}*GD5qXjmzjkWZLQPZ%km} z5qj8l>%AGHz_lBZ$jsB4V~suBBGFZCHa@HvPS4V>-( z`Dx*=^o;CsG^MCEa?KICy#X0S6DP>hKZ#J#;fX>~IB6Duwn%-~SL0H7ggihq3WL52 zHy3E}4IFPY}uo%J{Nm%sMy zA~7a0>xn(LA^9K)c(BMjjZ?dQrTQrsA$fQEji%SBQe(Bl_uq*s`y5pZqC~vSQH`g@ z>=zTI^Z7_|ylguhiAnh^v_;7^QpD*0n%rx?u-#1}u!2OF;-sjXx3#c3?qlXG0lb`b zJ{AGtNh8GhMss+j*`cE8tnsSB3(&1EGpZ5Mexb)f84e|RigpQjlk$w&%#WK*BW6nv zkyQ544ti%l{<+*!^M$WC2JtTQ)Gtn^Ft@hMa=!;<<6qP7EO;8QSD=?RJ7(*Kv@{oq zUO7H0Dq|-ID7EF2E1d^^nn%t@gHYT2{ZifH!ndZM$90ohe_aJ@#g(JGMCMZ2leEdu zh%LHaq2KDQCgA74!Gb#soea8`FW3){dd*by|JktJm*Gb;1=Q%)uQw)Mw#j8*e9;eMxi?i2mV_s-bh7cki6OJj~WfXg;l@TUqmg= zsCMF_69|M(jjghD@17p(BTS7ccWirT6myzr$Z;D`Q%9qEe;|J{5Y`9l8f)K zc#aa_pJ*bL2@7mE4BmQ$F=pWpa96~%3DeoaB)re79Y4KaHkM(ijQ#MkdcfLH<6cXP z9oo>*e`O>lB(r_$bE9t?uJxbdU+?GlyfUxE>!Hy!){okP&UWD_Yj`b1MwI1&;g7hF zfNzf%ys%WP2U-CeN7%Jz(2K20no1w)I_4InkK5L2SDi##TYY4EGf)?DI4zf2oFOG{nr4%l zXzq*!9rLrCre|fVtDT z3y;w)DH5%cQn?Zu+)>^m#PV)!YFQCu!iCRg;N!p~f;jfE z^ratCT3ZWvXZ<~17x;I$AWQJ0iQtPS0kBx}%I66#HwauTwtLE%@0btGqm~xBbk>zB z)PEDd6bmDlVxpD2b4kg3G&BC&lxpX<1ND zS)$v`=ca>x3w^~}f<|r<;`Tb!2WD#CdiIOFQ-k!>KB#EZ>tHMZSiAXDANHVD5lygV zW9>2j6Y7D=-1XYlp&TBflFK&vrZXsOWb%B7mI~!sHi%i{I$!;|Gw1|t>>7~#JT7+WWS+EL8fdMpNy4u&6Q28sszr}Yly-WBXz3P%?kB6vatTaQT+;_gt_BTDoeH*w|eRm>ib z33Rl4LQ+T$aau*36nH#lWSP2iw9Y;zgjINULzdl)IH+xLjhjWeP&#UP-5^vy-PqnP!KGAYa8V=)@NeG`1tONu=q0Y0Q&_s3&Rd+ZmaJ8 zfO7^9*#oK-Pw@DpY0Z1T%4m*nj=9Q`DW>U9Ez5jbhV`lg3jR{Q=QcJm%Gcc#c76Lx zOAC{mvYd6)0Mai;I^lpIqReISv%Mw3!dP-HXo(&91yf!BI`(}>3I+^R1jn6iv;}Ip zi&VNZFcumEzFFo{i4b4=WgykRenOvTD%kM?iPygqBAoV)a~N1H*L zcgECb=rD>$ag1AuI?Q)oTr?uCeUiRc%XuC=3a6QytpIEe{cvz<6~6R?r;T7>ZFguK z#uQoPD9j>Q`H^dPSJ7_;*P`$oE%Lg0Jvg9pOFW`~;=oYhciP!h$b46J+m_^QfveW_b z&4`F6o^qan)r$s^?+im<-pplA4Gp{W7lh`DO~-eQh`UXJN4k5L1ypTkR103$ZEu*W zx26T*)RM_wRXU@$S%ZY`W3V-ounPMty1Up=^vU%a2eSi*o*Rf#97EMcw%1a9t1+Ay zhI?TzJhR5GV32M`sqQ>iN2SR2H6%x$jOZ{IQd{G4RQSutqABALPN3H}t9zC$Gd`t_f)rSD*(&_idIMN(+T7U zK*Hdy5wjcD;DSfQ8Gz=?RJGnz<7Rof(C+WS#*)SIo8FWVK8`2U-;c55F|~^ey6OPH zMtVl(-UMjW9f40Y;BAs~c&idLq)YfH$SeXo<#{#VH@Kj-g!B8mo*Kjd4+x8Di<=MT zN~h5pjLQB--fj*`=7YgLi9kSXvN0QvtwZJpXU2pa~npL|N|9G(fxw zju?inpB|%}Pd2(#b_S94mLt|2Gmu4_M&<195-&#jW1-#%uA^MA>83n!&RI>NIzUnH zvYyX3!GWZ=p#p}EvG3a_JSyM4FK6B(=}BjtvjbnewiY5*c{WDyAu5j!F|#pADRlBd zYVwOF%jBn%$_rCkLxD$sL<-k&PfYMdBi?ICP}O^hlDHH=5TXJbaZ)5RLr~5i@W{NE z3m^^j>1EjV&7roZ>qRCnRJNw?Aez@A=49B)65{7EUToW4T6uz2KjKR-I7lrHF((r6 z%tqT?Sm3hn47keO-FZ{S)Bn)@4OH>cC{;;EZ zrGrsQMD%?%S(oq{Fp0gLxslq4z>P^Ot+t|yTn!b7lP84--;9aNkYS6o)?Lpk_R-KOH@k_L6R5>q^Ew zC*%^+E<-s9N1F7WEKhY}w%n$?OlxxyQ-ZzEEVrd2?h^UdDfu6KiA~BT-pUz-O_q?B za7>D|cvwlTwPX6t^TvlG1u)56&`c~0b5zClF5pUZ4+p3kqS)$ zCeDe=wBuR~AiiUGX6?6WY@DCJ4fF zCR(8j%4r(@@60R(%vKhfuj*fUzP&gA&z|GbZS>4-M?>do~F4N zht}?8-e@gYDA(=o_s#9``DgQ?Xbfz_AdE_@gA=q5T z^xgaCK^CpPKXh=!dy+tPa+!>ffVahd(`0?kFqvykPR~0~Nix1oK@-j&MzC_`z#JwS z0(i(*D#7xtyLqCz?zgS4nKAC)&VGTVIY4~rjFc{221LfYw_^4SyBHTy;X+%$H|HCb zls%SB6Z5SsYV4QmIcny6ZPwGb^^2@dnRRJ-k#JzV5sU={k$MC*)S_fk?JddGX(e)t z)?A8%)g8atiw{l`J>(|Qqw~ICtwFV<>7rD(rh^bzAki3uy`O~LZTw`l_BDyB+m`;( zZGF8dvD7mYk$?jPy~$?th=FmENqxDZ52(Na?hPiplO~l81XLXjEjM=?N1BqD59oXE zhk&?2iOiNRc2TwE7jP+&`YA-&y6FpEnU@O1u<{q19&h9`9CG@~t8Qv5t4wDeX3dM1 z=B>L0!dz|`C8#f!FQzP8eLLtG>OM_YB#S|3O5YQVtr3)5N z(2vN-y_odMSdP?2N<{jtQ~5Zg#{o6UL~Y^xozOO;=TlUlIE<* zxyA>l0QlD52nwA1A9U+5Cnx}Dfa>vfX*_U=8KNyJ;%<$n`H^VlV)ows?f75Nujens z#~hCA((0}`>7^LySvmVhg!Aoh`VC5(D-BPAf7aq6#iTidYTG#**oDyt3$K|AN9Cu= zhiWDd8!;WnrO2jrP>rt5!&I8&Md0%aQgvqi&K?d!6UhF-JHp&p`kj@_6>}aqtkMdo zoA}kXL@$ExNPVnQh=ErVUB;VKwP-4)1f5!5-*^z+LWMH?!T&&+d7Xsuk!XCbJYaU` zkA1mNOi&wp-Se77-T(awqU*EHVZA2NslYGin8e6EnIK-}R6Tp+j56_ISQ+$2`N-7m zgRJ#J)_BR(rf;&+!~O;`%6qGpc9}j9`OIYUh+&y%42M#tk8+M;p#?jT%E`oMlKw$1 zObj{H83^V5wLyes#9dr7+5ZQ09O{|%Y&#o&I8%Xn6T#-&Ol{LbE_N+s&rX+zh-2se z-8=9whl*lN!cZRkONN=H6qSZjeK)a39(7n63YKRfjJ%=l^|kT{|Dxhh4A>1dP6AmegK3w;FO zTMXt*S{ps4BX~=2whIr4>q33yyWq_zp{W>YkNK*#75I2seN_DXE+W3{o~V=nSOy^T zAT3?SfIH_gBX_ByHi@f~AeNJAkHOVbnpH2Hr1|=j+v; z$lJTANZcm>*^ldO?nZ9Ic&v!EJ+f~E7)7np&r()quM z)*}76ZcQQl5qskdxLe{FQhkV`eksfj>Xpw1mEq?1XQtNi2#J zo?yzD%TwJ9IG(X^0L1vqw0E!m9!ZP@IPGntSsBm*s@j@E*q0#b)Q1j0=mQRumoDqX zOfu(9mY8Mmw z6XC1^f^aB^p=aAPF+o2%dn6=pT(^@L&v@d zG--*yn5leb+kA|9WbmM-35yC5B0>u~BSGP7ma!*KA+u!D6DKRN&; zQbRwK6~QA^CQ??c#m6wXnV=_mW3CHynsgRKQr1sC#=H&1mb(wF5wp2Br(?7TRBhQONJE9>9 z`(5cgpu^+)b}Ah4NZJgHa71k8Jr#*&SOxB%e`T*Vr_LifX`!9KmW~H8Q(xYMpX81z zwfu=&R76>6s!i3&95QT}Z7*TJmiW&82bJ@VdK3BUJyBOt{8oWrVh1(T!}Dho^yhC` z$VQ9Uo_2)_k4~m!ki-gG$!j545o{)GE3SxUa3&}v`A|I%9@%bgX}J`uG3l_&&z4Uc-%HmjaIA~%U@p{99c+nCrgEp-Q-YYh0r4EVJXx&1eXQIqP zV+}tg-hP4s2G#5kcgevS%gpWlijiAlTv!U*qq8!(_$ssE`m|~} ze>ruUDck4;>*5*%zou}wwm+xT**>Fo2H}rj*vlO3Zr`4!IP&W_?(0?xpSDQ4Vgh9O zqg~441&PQ3|HzEhQ7*|e|kv!S)5&J-p<{^aQolx;}|8nSM=%Zg`*F8Y z!AXBZUi;S`GZ7_Q{w2Hl;Bf=~wiJ&IkF^cD|XdyRhI|;q*fAu`8BOH76 zOGfOmlhilku&JY8d2=mV7pe1#YXeP_cUo4mX>*;ShJbH=t#h53xo@pwWXJiFFI!<1 zF|bzwN2&j0P)+6Y%Ix2jFSa0D?0Zh7|B>a;ELj-O;BTtuFI%F`#(d*JU;K9m3oU;e z`r^yDCVB-vN+PM<1>6Wb%cfU$zQA894ntI4xX()lz_%JMDQ-Xg-atd4o$YqUUnItBsN9wOAu$@9(uH9}FC(|4 zhfn)#IlbXb-2B}ANU9m$7nI=~az>oNATfJ<#gw*{L&BMRd?2dMY7tGWn@l{5eURHs>%c*(TmShJ1gBZqK$=^lYhh;5b1G7XvB-c-eYLc{` ztBL<${$O}fW>%Sjqo>1M*wRsv*HOW~T~a2APw~QMkKGAx$wHMBDSyl%mq_XYl>Z=@ zMEZtx)A{n|#3yU|TrxbjR_B*(7SIV7F$s`p74NPpo5LVIsSnDRASy#0>zVL1n)RyK zV!bz8(uRhwQJc}sfc0CzJ^|-3p)Jq%5p42VM!6$0+%9^0XGbaC{z-K(TGSy74m(A$%wNQDjNE(r4EX-Yz;1Gm5Q=R;~4E9rjn*361kl9pM)5RoS{mH z<}Z|yv*zGNe`?s;tgpr}gNKFB(~f8GL1`2>a0=oogxo@Xm~bl~Rj2w<@pf*{NF6np z=&O8EKI_-fJ;b!|q*OzM)S`oH%$mA1UQy-*K_+HDy;1&LZy*9nHCQN0DFE(z*Z+y3ee*R*nY?iuDc@*?mU}S{<1+ zT9J+%!{^8P?*pV~aIeemooWv~4kA-R2VBP3w00??^*R$jN8GS1vq8y>?`=P+;wPv8 zN)4AOJnV1YliK_eS!40U6*ZOaGB`^6_uj)8wr^kfpSLoe&om{|_t2%5 zdn0_Y1%aI&7qkv%%Oi}3F~WE5EW6M626cn@T|_Gva?>({*}|M=X+P0aOl6+-36;gDtkc=DfKW7g$ww1hG;jLHvR;>&1IfmTDWT z(V3ZIRFqOZH5KqMP~i&R}{_Y^DL{qD=lStIn&Av=<-Nb7ZI2s!cA`&TedelxHp<6T3!I~Z) z|Ic-&VQz)>vq7hSEO4<@8&KFH|7q39wlvMv8@-vmywT)!lpy_h6}b^%V_&X!;-0Jw z&S3Pfo}6wYnNlN&?*rN@iVDL$biQ3Y(`BW1=lH=F2lC&H`Y`Hm6VF69z5FZKH$q9$ zK?_|Slp-TobP4kB@rw0ea7540(r1-9$z9oEr-wb_kr8K8Jd>S!otD)#JPjSVkH=@C-x3TTN9rqg>Q zS=`XREkmPNeGayecc~*}V!;Ehb7t`dxK&ABBk`G9$4p{}4 zJyLFrg(kE?!G?wk7x6tq9w!V|b_I5ZK(6*ijFr!;fl?WUx1j?sPn32EH6vddwkzF) z)Vc1mxKa7){v+G#@l%A?ggkeArip4tvxn8+>H$$0x z_H30*+H_z)+H!mMl_HX)k@}NineE&suoTH8Mz9yvjBHs~d^9AlQe0^`*3H>re_Jo<=2rMtT={t?X2`}w0_N_zpHU2n_dF^e zjDYct4bvs^Osy_kq)vXmWlsGs?xp@^$y1}=9J#&FUHsrf_YZgrRW+KZ6p|O}6oP0p zQKy22hlBr07*&apUxyr2 z8-3SM^m$z;9ob&umdO(uttF?aX?UMl$CPX-0mKJV`q1%)5c$DVBr|{p>0RDq6oX)b zJ-V(&bRaqb^I`$gFwy&h0Jx50#2xu1j2C6}FH{G>c2$pIQl{e?{b=WC3)A-N;+a2s za{ltO+YnF8PA5Xz$kPkphHLu5k6*are@0pJIAK32&VfvjL+2TA7qr-3ve)OL)xRATq0~Hlhc^$To}cH&ugWl zb4nUxyLd`O@93Wi9UWL1VY=??^6s8Yj)BhW1A6${4f3f8!$#svnx5Anq(B~U&~DwC z9zT{Ta{>E%&#+oYc^@8W-yfRQ`DdN{w@oFAxa zI9cOHZhW0%LoND2ab}F%TfwV&KZD+t#jXIYHOdA9z{c%N6~P}u!7XW+eb|b zO6fkGF1&VMDPyS(QDho$xGD=Z=!*B4r-U6T>0z%GrpITPUbJ_S6SP9STaUr06NfuJ zbeUond*cnfW4GmH`z@%2$KNZn4eGVR zLe(plf}k{8Cho(gwUiH27?5_6U7hvb3dDBsG9~1Ymx!nA6SBhWqA^8`=tM7R3lT`s zGce^~4&6$mM}KD$1Wz}Nk*F&#L~#Td6L+<~X|VhOpg>=|9q^x8u6|!XFkq_I!+IcF z#VH*`QKgcjP%1eJwoxVw?y$B*7_+m_QfGtfGKvdd<^AMi)h9c^d9S=kLibf2W`8); zPMsQ9w3O>MyQwd0$C_e5Xz~*#k;EP(ELfJ|}E)Odvpt zTfy+L$xqEsgg#9L&$bGlI%~6X(2!m5tBZXe+j2Gbzg8{zW(_j~++0Gf;! z+qo-8LpmF)Kf1BPB9@iRv3&%?fI-a%;y2WfuCkWFOgZ4xA(=5}pMjmYLRT+LC&p5r*|b?rl5E>UPtEK?vbmh(q?iXbMWm{t}!77hJumWbyHudoo)w< zMB^y)kAX6$n@5zkvapd`G6=e-2FG!OfT;YH6EFp*=)}`r-cx7*4_usVmld{<$~cTR z3>~1jH*c1I0HoU{bq%l65!{mw*9F1&FvP{#S^ztV&n>uClMJBtc=s7XgiH3w8cN6 z=G1LAL7e^!TatT(40QRa%kYtJVp|%FLWUjuDJir9Se^vEkaoB{C}iCXke*>-^5B03 z^LM(F`CpqJBW7kj$f9^$bUA0l{19!=2)enc>`Y{xY2+KK%2^6-sW)x1Iw4emwg^-i z8-Y{ZKzjS05KuYF`Pk=O$G%}A^X+64zY_`FIa^Ve?b`d}e5j2{PjgI!fpw+RNa=?< zsV-f8VOPaXWlNJ1b`w1U+~S3Rc#Nae{-24~)E_3PmBEh>7`|+sBx{Id2)Y`d2lr%j z`-HROni{<;f6iZXUuEzgzxugR8jeVRD~zbT&?c?t`92AB-1EM z-RGT^61)g%wHip(&vGPvIw)&yZ~;ZCCkSw3ZWk1!e(1%Dej3I_IV2Hi#{>^9J5wVF zj|^WA*almfx6i%`&dA6Ueo)7_M>PhkIEwZTqkyKMqRD4&>w;Bl-CFbtk6_+;JZ1T; zEKuq5oSn}0Ychu4%c$f8?1~AAdCS-x@ukd(F`V;a$438Pbgn*GQJreC3n;DQoInxl zYeiZlEXI{Xp!9ZA7yw4`v?DUP<8|hhMGfUh$3v6fnQXTc+}0g;KbL81=09rMz(*EP za-m8fht3aYJ_m_9_04bYsV=XFqw#(@AB8mvhG@=lpBXY zZV@K_i>5~M>XqB!<_T#|OT$&0p=z>MJz5tNJ1TxgDXGbV2Dz9LXCi!rMQxV!07wEu*6_e855Jxbf&fr;BT>}AsPjYdrW zp`F3PSszQLT7`}6yX z?i`w&KnGF#d9 z*1PtGy6b7S6Z?$wV_amCaE-YFyO1W@@7V(Kh#b=GA-X0 zAAfHp$cB-}Cj(d>n9a@c`!nhaPZO2##t&Cbr9${?JPDHflU-qq5Nw3 zY{U1l!;_zCqAlexRTGj^-s_eHu(KudH2q)iDsAJUkfSQM8m!nGp3ggf+IShucM`C_ zk|`-%Fjv0+aqw1xFtYBMj>Sa7yP3oZ{gm$t!sYsji$pgaD^TzzM$5kw`Fh{qHDqN$ zRv6aIMs%SSIySP5c*QIreLRw?(#+OG#ZB^_nWgAZTYMwz$7yDN^WUycFGr9yf&t95 zke<^J1aoDe^RJ~b54-X+{eXKmipkCF;;dX_imM!`Fxq0nHPN(MA z82KmlQlURP5WqCO#Wjr?H5 z|Do)=!{P4MMH3~69ton0gotQi5IuxM??f5BBzo^9LWrK|y_e{so54g0LG&`(5WNhB zD1%Y%&$rLM=Y0FzeUAH&$K$bn>s@be>s{hWQgQhce^|j|r-PLwUt*)<-8RYhi?{b> z1Q?pWHwv|8*{0Z*Dx14?D}YvVNwW}@b!Cl@Ar?)75UXK%(*!LU(~E|_6n9R@1SY8d z**Ak@y}mW)J@Xj-=BcIA@|)eySCc`ywr_lgaf8nCtz=4xR3c6;S9A;=T;#DAdXsud zV;5fS%y*S1#P^y{$=voe)I74M$KwV)w@}|Ww{bM$c&sJhHH?XKSZ}g9}p@%r1V z9p7Ii;jH|i;@Smon~=*{uYk{w3Y}Mf6f;WI-Viw1#M6DMM*DjlKCd|SLxslG^<0&` z)%mde&sp26+Qz&u2}DZ%S}fZsFN^DTN)K!kM)b!FcS~>WPcyFp1AjFb{U5NuQjnXD z=*4_XYN!R3l^5b7Psg0eb}F6qug=Map@-_=A0_p$ZB;P%wPpK;J}X_J%N)vNqWU^l5>~0p{kQFf;X?Lbr^s(uV5i(vqwcl`**XBsJY7(CtnI0+2;bT0Of~ zTc4L}59{j9^eVzzBamer;nQ`L9>dxe;brEc7xP7VhXpzvwoWUPzWXG~b|^xwrU&fa zYwS{w2Y`Dh39W1zhU8}Ka+U>osG?(}UFrI?9x_rM(C8_^7`$Yv!)*%-+1pQmYXb1> z!sQXEofn{E&f+WU|CYB?>6=Q4N4BfC+NCuD&T zls!${&!70K@q^-6CT>gIZf-MA=@_^wxjSJ<5_VoB>QQ!)`K0vMvk$%0y1Main&LBl zqv44&4M)umqw$0`-4Vx60_eQQe#S0Bv@ZsEF;6!}j>bM3-qf6kGnXk&{~DG5?FKuJ z_i$r=nYTqbH+w)2XI8#Ctap(^Ct%78R$ga2QU^tOygZ#an~aIkz|?i=AIw!dC1Joy z8M)&9>wT5%y5Zj%$FioL=yj#~)hC`Acb864Ug>(mv@;ETdth3IgG=Aha-RUXh5uVz zj10P!T)BCrU<9WE_o~a{#RPTz8_Vcr;kM`*fzo)U2C6jh?i<>^o8e1WZDux{$*^2Z z0x66L)17dhmzRdko%&YC*XIXDMW^ew3@DszKD}9com|IDxdE+IaPLr{cpH_3fC)XD z0xmC(n&_5({&BOX)~BvBZyfEwcpl+emKxx!@onEi1=oc$$L1iCB@gl@eh~d05SLbnEmy=u|@vQkg4t z^sN~MP`QVrdPnkIl5AUEpOLI8wjGEDG%kk;C?0>uE1)tIRV zHrxvD^ZbHanvFLyp6vQpeg&U%rsMC6}iXIuRBGP$SN8G8--)jYg-n zg6)x#diC2QEe`ibo@wik%Ww_lz{RLSz-ZrO$Ia=Tw|y1;sFocD@N2EVCmC>gE^bhNP)x#Ll-qjR6v$1F*zp@rDR`V{$C<07`Bg=DkC z#81>la2i?l3$yH}4TxO>Ds5j$Z}^-?HH<#ojpS2iw2ThA<)ybJPO`1wwb&x0yZ_Fh zWqNY*b0&vKPHIcYe1?K#so-2>VHoIZezad*P(?2`M4Q9H+As7OXp%FPC=KXvDCrff zBOCf%(n?QU@r!?nXpbRb--C0{sv|t`mYn6M`PdVZ{*WFFXObYQ6>UOukj3Jj4Kmhv z=*{5gk`=HgQ=7}H(DOrP804-DZ>4}iTleT~zSrpuyJ?dgMzii%Wq1{)&b!s2HzOSn z;|0Bwd`QHe05?}x^7uxqoUGjzp{M||zEzZlf5A-$bI6?b$y%MzH&JF*aGZR}S_ygi z+$oPT*HQG!hHcG&rrYy$s)iM|j5L>{soawaL$9_HVQq)=?7$x?5+_d;MeG!$zm=rb z-OBaYeKY7JM~Dt>C}|P;+|X9zD<`i_`g&zyfF&I169;AyiR$d^92}m6DKhM}%_Yyket(?(h+Hn8$k5f`=-zb@TN5s|-7NFu5Hkb0g&&Ta z7SNn{{F=12N-R2D?vqd7I=dPeSt;`ar=Pt~UUKeX)5mdvQhX=FT6rd~rM${^pW*3_ zgW>Rw?;Ac1Df!AboiBQ<+e`Q6QiC&_j4IcovvanV{RdXStDgmEZ^3>QMaRs zC+!Njurr+*D*YpJuqVH;-0$ho^M1YFZ1q?<0H0Up7W>b!Ckmi)F8b8NfD4Yz0wH4l06HW%+yZ@RGhv`P3JWexh z&erC+JlvT97#IR90US|Df08uu~Vx;(*sxh0Gc%L}KMU26H`3N;SX?h=b}FWI4}?w30+#rB+tui(=oh@=(d zBBJJD;$lL@#jmLae@!r^B8qwNlFIkp!~0ldU&Ft@V)Tpk{RYF#VS4C4arN?nbhXTJ zKK#c~fR2-7Q+xxDrSgSoq=WLt7lMnZ34IRTzT@L1m5w|W(R&y7zz=`Yd|6KJI3gI8 zC1m?aDlN%@IeNaEY%ZhDF>N7lWZz|u*leOQBq0_1W9~fob&Rv&*J95hd|8n_oGdQx zC|*U1s})%E!JbHvmuA~7-;~g zD^#nJ-sJpBE#hwb*4jEeljhWfJeT1Uc#q~TGh|Vpr5~8z0>Y`lSkW=TaxC5(ELerD za;?m0w`P&yOa8|fZUj~+NMcj3847WU{yEn8NV<15ClO{~Gv3aVzU7O>-Fjv%w6MG% z`!U+tBhF`#S>%ElZu+vxMtBk62KpCHn~`R~;F5Mi?iM}o8pxI z?o&2zPTjAD?2g;(2`|od-VAicQ4N0lDrD)OoT9ja16-B{iXTzTI#q9ilSk&?;N_#P znr|GM_uSujY-@E0+mwymrYK1o>Kcm7leEGi|MlrW{R@BnA5KudK5)8gK(35pPxStPPFh;=_0Rn$ty>9zgi#sLrDH;`H6FCr~boMVF z|4U;3zUV)8cjXHFX4ai(VD|H)a0Rb$lHj+0a^97Y|38=f^RGi;ILkC?cxtvXbd$9j*)!!k?<|Fv| z;H8U;%R0Q$=(8yf0Dhc+)AhkG#_5Wtr@ci&_vyjQB6U{h|K+&0uFX6>vXYd{ z04kCU%=r2FgAH4}O#osHugPBf0Iov+n2AjCN+I~#ixiaskeT7sLAQwID|o$+w!&mS z^_*ZeQvDl-4UDDV|K}`#|Be^>SCZjmKs$~XwUDDRFb>2X0m;E1cJd4(xIP|~BrABY z*x~ZxTrD_xcDIS~-+=P}+@6w|>p$+A4;85}0);0MPF~=;;`Q*cD}B|w-WG%x+SS!H zl=q6%!0e2SJJ9F9YqtNs_g^~<@#1tv-jBP>?2X=`hj^f(AH3`~enfd~DFiO|01PxX z7H?o?OuiWEi9JhkP0()ylCT(4GSkq|RN)VsXolfmdmUr&`@77kX=!mX_>Zz@21HQ8 z%<{=(0qO3WJrb{T8`-aoeX_5i-@mHmwf}All7{)8kE}eF8k7EF^KVe~-=*icjo{~Q zN2AkHd-jW}o6QlC_9m8|y<@i+h5uk7MT2coPij|oO zP7R2x4E|ka*0zr8FNEB_dEfs^-hpw-l}4~#gvUG(j+8cwju2e;Bj59ZU?8`t={diE zfGN4Dx+q=Xb*Y|RdS!5&mbxCnsfme+b95>V-vqBe;f`^=w#ngP|A*C=n{vD=C|_&m zK(3d7vjI4|K+(AeBs-WX26!tU=NRRHyQSA-*YD(?A9SuH88HB^CN-ch^c(CSO9_c@ zT^sD7ANW5(vH}WfAZP>F3@BFKk zcWv`{9eZs(`SuZy<*#JG#|HwYp%x#HyUaiDUla2;@m<0H#l+_#TVJV@T$j-#AO6$A zzlgpbp@A=F+fY!uZLAN?iayp0eoI8bieq5rx(%1xyzX%|1Oxd7p^u3o!^zH14+(F| zd@2^<+da7EfdeZPjivZ+IvssX3JFx|H%Wb0NPvL2bw7Bi6Sr9RYp%b6GawqEsTutC z8$P*|pn=)vN7s`Pz{;&da0Xg;M|ir^v4QZ$Y<;SR4d8XOR_t{Hv+rX{zcDBnsTG*# z2@&rgwdDN3* zbYL_7molFi8oQDqHP|Yo*JRxFX#j(lv4D~U9^T5)_qbxfhW`%+d>&ZCMXd!WXh7DU zN-3_K1a@CHpmu$S1*{treGKV(+xg&Sl7HO8|B~ zBFAdbFvqGg6L5=q_i&Cki78LXFoegU5@ycWHt z$^~YwPzBZuFy33G6XH487!?!;Qdt`CnYDM0wDYZb$u^f9U2;<_CDGKVtvMrh?V=- z)n^(kH`%4qU51m_Y0Qk*>A_~f_6XJBWEwuKL85Ewg5z&wKwjV`cB&NY;(U=M2Y=7Z zt5Ov2nlfNq!ZHN7Sgy%_(a)s;!*4-`6+xx}=K3A@|HTJ@LJ;ET7YJrR_?$J~Wu7}b zPGcM{T~xa+9x_ynqu=?sT__3fkpL1Urx{Fr_bTG&lyZGVo=c%i0lMya!r6w#fmR(r zL%atpTM_TU`Y>>*hF!e-i{v%QD#>KHpff&e<@I$#=IniZS2vkYqk~P4iEQmj02d*S0T9lNB&|ue4VDf~WNs>s{ew*)?R zb;$x5Al|HNBO_aZ>l_s#F44?V2Rp#a876LCF zEHl-;XQl5hI3;-ppI|Ch2`e~tNI{A!@9SN5^|G&b_dY)U^qTzXU74GCBOixGBynH7 zd{I2|LT{Z@^7VUFska2oJtCJiDQQzZc2Kl^6BM=}Z7*`@vl=h9pKev*8c4=@pZQmB zneAd{7?-4}E|$Q%k$jRMWF)~LxT=xQvO|DzsaGt zhK5Z-LIRG|L2_zOIMe$ZSor_Tk0Fvkb&}vW5Z7Wb&xw3#r9-X1o13<_tn4Ru&6~0> z{>Q!l0a^AMe!MeNaQ%m8QbeT=RnyaYrC*s?UJe$glo9-|+XE18lRZ9^{It*2I!i;7 zW&o!KagpVIsNkJe!=uLiUym<&Banebbu*A`&B$3MmOQtj0+x_43X+W}PAqtdM{{P6VMlo)B>=qNC~^m%e~>3^ZyU!)z$AWCN*Q6frzf@^)J=8 za4XkJOd`i0)_B5-47|=Ed~oE&$a3Gc$CQ`YyKz*O$Z5m=Vn~h7>gA4nxwvVw5xcGw zsIgOnE+r+-b*xs7C*l|g zPLXf8Cxl7VJ^Dq0pbO7^{MvHO zTdYf;Y#oTn>MLpO+)C82_nosGG)j)tSsjpoIWLv#>8JRvGUAY}3k9aQ%ry`M_%eZl zF6o*I$^~n=4pRgz31<)Y3E*Nj5lK&#g#2sZkO>&XCR!y9akxYPmq>dWI?zLU;hBDz zL!M@xD*L-k->}+h{+Q=v<$ZtX6p2k`;|^vZzI(fiZS@gsyMCC)z3nD#VT#n6?|8;h z<$$i)>W6=kK*^22F#k--z;oknsYf80UrA|sNp(1Ye9afQ5?e0A9mQ(#=L=uKsd0ne zmANK6Uf&9aF~2UG<9&+)g!!0EGqUFG8K3IKrh3#1BFlycEq#5=XshMj>f4UXZv?Vb zc#mBC`HAeg+uEe%H}dAq_hst3G{R=gu<6Y2coBWh74bBpx_K1TzZ5m%_qMOK^m{l* zD`?`@SjAcJTcHdi-*0{^iHQ6b&2lb9bp=WY1 zK!GfSave24BT8Vb%t_}!_J*r!TNgbY!8H>R{(%s-a51NP;=1w7MtE;xx#e;#LBqXT zo{Ac!@GbiMWNc$#8g>TR(>ujF87mzzQkeL=xUU;x70}@`%eh4jPx8-N14{0X^E0Vs zF!b)&Z){rM8^NUhKLx%xHV@nm!KZyu!rS5MIVib3OQ^jZLR5%R~Zc*WhTqL=al5TUK~i~ZR%Yl zhc2Qq3dZcJbXgIVVLA)e<`z8AQ++7kbX&Y_QV;qTr3QPUo!Hx>GJIOB_bs^9rW{5= z+gpD4sy$X3wns>)?T!y;ikdkqbVsiiWw$?bFY3$#dS2;OH$AraM58a!YBuAP?lSW< z2M@MU7BcO-+3yz9ViKwp@L-r>1H#*Mj;EjU45~)<3HKSU)Z50TN}n#S7IdBYUEJ4? zRUbV4A$+u^Q6yq>c^e*sF5vvE((+^*WWGWEUtO5M9X8e8K(b!^oC;pR;FlE^PCO}n z(u4m+B2Vm8ONxxY!vtDm?aE4R4Bm@XYgQ; z^&1|YCvA*}y2dTYgrnt|UhX|rFp>8$*!?WF`^SfabF&F!XY3PAUp<0epqe^Dpv5o7 zEL--!fSoSWwTTC513OZDa^OM&%kwz z;yBt55Y3vtRkYI@O<(IKy~*bQ(awGoWdep$W=NpbZSvKuPhWurUz;JC%o0*3z~W^1 zCKI~Ebte;PItUQ7zHe2jR8I@{1z83xG^vZO20$J0*}U)V?5O|bxka~SmyO%Y8kO=M z+i#rzrn9qsZpV8wb;=|uxd3ULH+4vw4g>hC1qGY3>&-iy?2c?osbgZ}`vxUVgnH@} zYtKFBf`~;f63r)V@6(T2gg}1$yt_V>(nfZ||AEV?SY5@Py`S6ZoD}1X>@2rE`0Rhd zQYmwXi7fZ^=SMs#$M0qwzjzp0fuJL97GKJjYfziTr;HaX?9kO=LG?HY=G9KIVbau( zB;UfNP-3GE8kVugbC^s(CJH(V`)iR50erabOX!BGZ-?cy`m27sVNqh+uws)5T0N`F zQy8aS!J6{<&onOb$J%CZlAiif4b-xMM#%7o&#{;xRn~mSJ9mEG!~bHZ74Eh*xc25X z)606!Hir$IKgBv5T}vW=L(Gl9Bf=|7HlYVL8-ok#fiH#8VUnNHL2YJW;p}K%@s2$h3+XUT+V{x}NEOziDcF7a5Z{9ln0^gHAbZtzVOA^pyF`M6> z!eVZR9Ir%$R@{}$Uh%%{hjd8xW*Tm$SVd_F{ zCpO<4#lghPlIG#DsrnsYpPz;G7W+3ONns{~ttTdb?jF2vO$b8;A8I$) z%{K8N_V%PbxJ35nxl^JsPb6l&I^_{R)-jh&-g%n)Po!s0)_rC`k5De>6e^eb++`Lh z|ATkVnW_lC(ea>dIK%RQ6}Hk%hE~zFi3LNCfzju(-MPa%4PpjjQ#}0?O)9Xx9HoG& z0{w6;YmV*54I~@AMu=8)@(iBV@|T_2A=9tMF_nni?HzdW&3C&sqff-cd-UBNW5<{MKkTx7Vvj_hgjXw{Dv zzqeAKP)eI7SRR`$a(4Kl-m9T#E_Cfq#-)ej%#Z`0h49G`C*0d+qRHm{i~91JdK0yf z%o@aV_ot+fY-I3!yDq_H(&ZP8 zeb(1+wt-{|-?*CXxw^i=%H1F=N0mo(mo9ePm(a}#&cVi|vYDcThH!BXiWzFEt>UMg zDHp9o-P{Kb8TFZ2XU!e^-!4etO&zF92v_m8My5f{I_j%$^!7(#8^$3}{l$^rAtELY zSsR5+(ucTM*^P%|2<*yr{4)+qPSzc8!TT+%NB0g{$Cjfp`cPyzw=Iv*_WULd_pFLu z#m22ia4+FO@q=D0+U)@m*ZZvOxBqK+esJq54WYUi8o`xjEe)r$^urt}?3{lgfAFgO zaEfU)z22pZIe|dx1<8{ukz9CY5&csrPT*`PQFaJ1;4_3EvU{hgm^5-m?4jX{k`SAH zaxb9qvGtai59)9`f|i5?raV`gGa*=FaE?$ike=)7A)fY>1m$J|K5P$h1b5SloQ}Jj zAQzXAafjyjmqL;DUl|1a3K8ocn4TptZa-^}c8yAP3X-3cJc%P zFVB6_rn^SqQla=Tp86v zjiXw&?Q|m8J-t!UcEJvRz1n9oBalLKTz#*gPRHBF$nfkW`W>zL(l7kYm^bHlFtIjb z{IgydhtC2(nP)9qcaAqgD*fljJ$gH{BZ*pr-D+AW{q+`XJXualxxTJ1bC+efYAl34 zAIFvb3Qbik;Kb~#T^vh38UI#T{0=jcxN+=skjghIu1(XD;J zkDhe$oK}l=P7xTh`y8IQ-;-sZC2aXNQ+OaBdDN+5JNq-xeM+$FA@SV{krvC+8WV6N zw%!@PE1#gKfVkht5l2BS_p;FXn#Rvk`^GHirTt>Lbkxy2A_i?YuETMp|h9n>y{U06YwhWH5c2K8PHGbd7Ta! zNbY{g0ItbuxDlrn1dG43T$l2p47RA#kVEMg z5Af{3sOVQJwW-^25(qBcP;Dbw#zn{$`W}eJk2}?nzXW`kq4Z2ZySro4#b*F_!F9*u z1>SsyFyFTSYG|JuA{LpPYaGtkDhkoUHn4R?@y<-X&=H;6^zIonS_=bWuEEy3t}oUC z6wuQX-W2v8xNIAfOA5znSZ=I4W40Iw^3Zi_(eu}!2LJmEA~Lj;%+tNYizKm3n#~wcn;P{O~#t^$k7B_aKgO~T~Z;s_!Wan zm*$Er+C(F0U7g{H+emA@O2|@n$nZR8fIIr3s~vfgqr|XZkQdiaEz8!o_b*+R69Fgp zZ>b;27|N?OksY-~@LOB!`qXKf(#MtAHj%b<<5u3UJ@`asJb|}SbeSOvOr6m%DEGMW z9XzRK*t*8d{)fu~dreDyZd~@QRhmZ~cjn#?_XkxCi_s~g0;)7>&Np^+_yj`UCXc!U zibJ97ts>mRnp#V>EgnxVGk@G8MSk{8*+P371B5-d=ri9vFlhi!urx;CUeK5yv_}OZRgOw*drb{Aik}4OAK`C1;4Q#K?4~P+w=b7 zBc%CsZsvnzdXY21{^XraAygMb0zdGaFmJ4zUarucGug;Q8D=zq~3p8@_4;?`xP}Uj61@UUZ;F1<>M%mw(|BXd? zU|zw!U7okOW7eU8Qrx}_b&!}iKWydrqG2Geg$8GxW}^d&L0p#dbO=Omhv55lCmZ>_us=;TX*8gH1ZMebFhL} ztlV;!W=^m25C7Ws{A@b~9 z`qAi9bH9$$g(51LyDL*Ch$|xE1J57!Z856jcO1y}oi&MN2}{4IjPvhK*pN$c|M7aA zs+}hwPF>jI`D6G+#RdZPq0$%IQ1pD)qq>h=6pDrKAAohNB}i)i1osu7Q@dIu zrn?rOI(!_P@nl$7I~LvxqiCoJ^eb(D5sO|p5wZWYMFNlG;B-8Y$?@lI{2j7A01-^J zM#exGH1=j-Zvx3q=rA*SMGI2->I)sL0SVJfoBLkWsT68Bur%SR{nF7Ws$yRWr%uBQB$?+Fzq+HF> z)Ie0$x(pGb4p!c8TC%-nv z0n3K2z>Szs=<(!>(KjBiGuR(p6kqy^%aQLCFzy9F%u zp@rpa;p0_mV71kWB9+pR=Mt!6&@XQ?yuo9W4n-DuM8#98C-U1EEwrZo^(2sRbfcWC}u5a5ty3N~6jdUNb_cuJVW*#Uot__aTUb8)z=?>>~k zQBD7qTpSVi8XyIxVkE7S-qj{gv)tQsD#^EKDHL64(jngnd&hVj+lRA&{4)|_yt-zwoM<1@w?$z9@cJCX*ee!AK9#{%77Pir}_FQKo$Y3rG83#gi$ z?zXWHRL8OihHa0Y+tTzMvQRdUgq-hG8Q6>Vl(qAvf%8=KW(hAWec)Qdgbse`>D-!v zermE|^G(7=t)fMKvsEL*fn<6lxaM?+DdciVRMw6ytn2DOfJclU&yLg2)cOXvBS?aE zBNl%bC}J|R5(D}v@tvZPscT~^;QhCr76?@j`g1UL2KvO2{ntRY zY&vl7r76q&kKWrB(!odm?ZRkfM}%gRMy^8Kd17%yQC0KqK7A~cjMs_9rEL|%?ZhF_ zr*KIBUU!icT(FGM->a5*d^`pcub!6%p~AaOpLAE2p}H71 z*^*on)Ytt}Q{NoOVmb?95RSw0XdU7DP?{+Nc{7Q65nbghg4 zdw;JqI(k$3H01UWqQgx(*Q^ZkY7~?sf%kRzEI{IZmhc57)c(}s7y4{DG-j}S`Z8ek z*|^;%#rb~|wzU{9UV{1+?rDG=@hnSfCC(eaWBj%P+AV2Zb1t?SP&%2o%~ z^jL8lHU3tT4V+{8tNv)CV zjk61nDD*uve+{=@3?}+Me6tvY`|<0-eA01GrVyEwp!eXMk62RdkGk5Y+?ySKcu5%@ z^WTSk+hylW9Z36+{z{)8@AiF0mD)edsBiwpX{f9uE!ZM(c^JO^r>N3C{-CF1zQUb2 zgrd?=t*(GR23}?ILlE*-0v>13 zdQ+=ob2VpVCA45jm`37e`c6;nZqMP6kU_L7O2S>GH`)z+cw96bZzm;K*OB|{naV?jCx!G4$NBZ4;%@XF6y^+ zGZXVIQ5MW}5I619L}R7StHVcXe%$wHxLrLwdP&3m)TH6jskpDOnEjiLbxHhjzkUf@ z&vEfP0>UAIAN|GJnL-+&VXl}=Ms8o?B65!?a?7w`C#`OH)w*w`{o@Ijzz?)Ur3xRm z+e7xvDs;bq*}-C@MF|^zZ?Zs&g=Wa%0Ke%%vB_%K#+y7d`LmZT9|YSqFE3qH98308 z3aGE#5>UTHqpY!80$CzY#HUsrJzLz(V2c{y25T?stt>}`_ieelT+VfW8}FJLgU0ZlBeo%oWhx(_>~U1NZ%@=xF|#|-k28pB-wGc z@>?m+n59K$m?sT-iX4n`y45U&wCgi?b_se5r> zbNrne)UCf}dJj!%uQAw3Tc{B5O=s+2L16cRpo0N90v4oNn&b}h-E`$Wsx+m$>jL45e0(G>q2vVK-L6$upz{4uk(TPPAq>ejtdbVMF~6c+%@7 z(CV(>L8A42!Qt{;-MUrf+!dqUjr83dCq;-6(^L3`#kie{&s8`H3UR7%a5fr2EPFZc;MMmr?x2I-cxo6%#d)`DJ!*ZCPSe&BHrgwJ zuAwh8%1SKK??_|Vus83Ha@~09D&2Astgl`Z=`h_LNOn8_E!}!%RiylxrYm*4+SYbX zQTbu#8=qc|3ZKvA0X3%3A1|K8p)%~)4A8dE-XS!7wvM;U3QI&!=;jZARM&@_)euPm+$UV-r z@(ONy(94jU8hb}aqmOH&yD)mQpG$AC9kTBz6yDMX+*6uc!krjMrt#eG_ zD(94~1Ti^#ULYV)qlY_vg;cLh(kiozVodo%J{~?F{RY|zVMR2}bDK4`nvm)8Zu&JE zZ3>kjBY4O(`m(tgWG~N1U_x^4EEdmiD^$p)nwB}dk>E$+#n4-IXoF9L9~e})qFlB) z_AY1*T?*0+A*kD8RKcTTaZ}=@vd1k0p~$A+(negOj?$P|A8VaQt*g*w8`?*@MQ2qP zT3|{8$2E?Nyo_p$a8I3yZTv=K8P`Wn_) zm73ztC92Z~WuHNnlk}J+n3xr$f+(T?b%CmtMc3rx^&{mMxVO1JMSMt5ImNgf6+<5y%efotcT)C1@|Ryv}E$6E{{ZFLM(}?1oBIGmm+A1ltoVcYUUIQ zqN8cu+i7{69N)7R+7d^x&84PRVDaAlOio#_2qz{pYA@1l6+91He#d)WD4xDlWOOb> zh=`&_9Pd7A{>C_Wa2)P4qQ5b*lp9GVo)?_CtYfBV(9Sl#RMgfX`AO)_!}Mr-oG9Uw zqcNQ#NZKDfJ47s2b3s2G=fBu%2R2q-(elVN34I_fhEoqUe5s~Vw;Pd%Ts$&v$}qaxId zzCTL^Th0CFU=uloI`vQ1^8x%$uL%}{Q4rk90g zrI`kEyh5!UkNgYmskod1-C7BQcIm*8-i$j*8=10bt_AVb9X(bZ7A4*Zz+rbn?DeG# z+887)`4vzHlKl{(>O|4Zrz>cE3*W|6Q=@6z!mcA~9J zjMqz@Yf(x5-^|jmVw}fm`&njp_MDi{I9o3!8lS*mc8TYkg;a6q&09(-wu`x3Z^xoS z!k^{-R0mAEK#FQ&z@lW{{?R8v{TxiB5wN2;r2_1|YNDZ$Q?an5!L)(Bj%Y3GZNyDfe znI@Hy<=qNKOiV30iCGsv9gqei-f9UrEp}Q|Je;u^$(MW7f>`BxV=%TdI1Z8(s`15U7KYkH zI^G{`k=P)#naWv8(-ZqaIj^c9Xjq6cd~Q)RMsWccJXd00C#Fs#aPM3>`0}?&4<$Z% z(F4-%z9Vr(Bp_8k$G$S$lFCQ+zS!>-B$GmzejR4hAShaL$aI@H`dO>E(VBHJWT26V zeGk+tx-pXcq$cQeU~c)~9vCN>_+pPjWKU_^QQZ5s>#>T1f*+_SWgFUzTKBC_kv+iV z&sp{1f2pvyPWO#amq!*Bac_KZ9+N1~j6IZLk8sNq=33|Q_d~D3bwct8U zi%+hiF>}I&?mRH2Vj@p69Undpu}zlJnY!W2nwF(V{qEJyBptWx#Gq3b0X=3c3(~s> z7mM4>6B>wKVml2%4jQy^dH*pYrkj#af6l6((eIW%=39*`b$3Z9*$zCtpSBr914(G> zOj1;-4oOK^{7ofM5s=}Ee2O{j=Zx|;=`fmgyf3(Ox)%YI%k58{m|l8v9qgk3ht$n1 zPZlo=)G-K$l>jrxd8KV({UP=8`>23_h=R@R`>nMsBxnoP40w|>{`a{6Gn8xqqcZdB zkVQ4V5H*-ExH3Q=Z%N%n8e|`;QZj*U4EEP)?*s3o&-0Ky5G{PH@qU2Cj=d@Jtaj{P z^kxn>_&)xZV&&jKvXlY46u_NUb7)bjhx2?s0BSGw5hSyZ@1KRF>?_`9_9dWw3LQPn zH)=huqxLs3cJc+24{|prJ}!{_P;x^_ZGaTk72JN#xxSr>ZSE?@fY& zzq{@Kf#v;aVclK&6aKe$tON7EN>0tv`)e_EB@htMdYWL*mq3pHrM%kxB~vi$1ueQG z&F=a1ss1EBjYLZMU3Afz%a1sS)2Ua#O)FB|349km|NDQuqDIw?wyV7&J*Gt4 z+3Z}+3A-?I)hI1zAy}6QRhm zkhvFa#L{lv*-XJE16t=~sOlZ-Vn5DI51|ZGpvi>6`qP+u1T^GRgI%-elz3=25i!*c zwm7ze1HS~rKW71?GrvrEFoOHuJT1mwgR!&sY0hF+g{B7;5_%We8gt;P;#(S#DaP&l z7^L_t@HeBK$~}pw#bd>7M5`?mc2PaXpsacXTB#+T9#nTal}; ze>eaamQn+_TvRw2*D?*Yzciuxgy%#0G8yohle`#xO<~P@Cz>HNepFN-5~HIi-U*&; zH~8(0d-zWKqYibwBX_xt3I|PO3rxo_wit^>q9z&>=X1lzL(T-rPo^1!i>+Q36P4SQHojnVwvVPU;FvDcQFQsvK^K)J3u~vpB?DXr9PbCepL_G&+?mT z_1*}VRGaq$C*OSB>K={M)iG4D)N3$3{s@=8aQL9OPZ%WAVPi?0g?ytEX$D)3Q_0}! zy3mSTf+Y%q!;sp?f@Y9~CDh`c2*lo!Z*cAO8IWJTV$0pdK@UZ@1Zt=SCf$x6WGKoQ zKqM#F-yZJJ77%Cbhz`wLLU_o!AJc zMm>tejoqixXpa7S1Nih%!(G4o2)0ZPT{=m$yMu@6L^_qw8orwuy(czR=5OIQO!2{6 zT@@%d7`XvAGrHXN$&-%5%A$V((ohnU#4@wiV?=A_WVF9cZ2W0$bZ#Sq1vJCDyQ{ND6t!HA^fPx8bS?7om>!()8)2TYm^DZe02BKTv{unheX`rBa zg{6KbCRDVAo0tsG4J|kk^&_5-Af}MEIgxJ zx~eYzf&;c_pk@D_$Pdsg=E@;%=v7^Y!EGiFgDPoH#qHlT&Ep#Xh&rR$84GAJUYotB zo?~5mayXL#R1&jx2qp%4@%Ne}#6JrM044okWVP`^5zw21Vtv8y4WxDIP2`gN@~ERs zng%d>A)$s~V`v82*xG6AP_4pVgn#$xEZO(n7{>Oy+|TpA@7?ox>eKJPVdlE7^E&q9IFI9d-j4d%b$Umv=A1UH zJ&SXluW4DW>IPOrjUtevc?kF;485DCe^Y?xex$!w~22cbWcpDG=Fv&M$0}QXt4!V!vw_-@-Sawn30*w)N+U zZb9wCD-g@fjfMpB5xePq%TMr5mkU`vQXwpchvhJj(?pY@8oPVL+$UB_qT|l(@0V)4 z>^!OY!7^&R-Oh36@K0lk${!Tf9+uc1C%~Uf=8=-QWTy39#jp#`h)<5q;ulYbXd-XO z=9Ns%vsc;-ay2I@+9nC42S<_CoP4KlOr6^BwnVMb2&kTI{ND=i!mlmXOWO7`+l;J> z6-s>1LMoJ3jm5vhK;#6Q7bp9}8*g|e-clcE+%O?~|9orTM zFR&&Nu&}?x_k=R%K%uLjYu*~=2R3q}jQ7oAB|5I`PGMGMz+okAs6DacuPO)a*N4y#t0$Ov zsPnJH-s{{~SikAvMiRK+&R&F}gi6He&N{=ay=vVb<~4r>dQNgKaryGMyJ(~JGqeu zhSZHZ9pA_LiR@)qC#zOgb;%+tL-@~mPa`KSC6_8q=#Qz0WEz2P96u!nMY7FNp*zvs z_lJnpfMJI|Z#~{+TmOU>2*fSUk6SzW>Vt9IYQ@&ur$h8G!(8jk`&624)yW;@o=uyi zHC*o+G75Vu^KV4d4BDjl%*bL!T*79R{w4L3dYN#tl^8zGlRGL!hCrF6TdVDa+}u?kd^x;v=N7 z)~&B`iAgG{4HNVxFRIuUM7#e-Eh+o&_QlFhoduXx0NSP)RZ*d(sUyuQS4gr_(?T!& z{MnVu?=0O}e*Ex_ObJ5clHQTY?6hW63V1mh&IIPLVMV;QwS-gcld3dFonua4gx{g) zHh8vD-8@M)v^tqfdH-KdU^-iLeSd1Ga_9$2_ee`#7?dr(84rJ7%&jA78u;0H{PO32 z$13sW^gmL&QGu2(u`u@?6n|x~VT70AAh;y0ee_4og~vTXeL8t2j~rOC@`qj^sys7q zi8rKsrV*)0H07r=hN+!69}WnSYDlc$6eA~vmiS~gGPoHVlh_6`xb22BpJ1iL;e2rA z%!byO30kPSf6cxv@P`ub^5>KxV3+xB^sDC^;lc3?uf1P)9^np9swlK=*@|vu97Dqb zxAup&JusR|MT4wmGOl!bsl-{@hQ+(IaR@)MmLqQg4BEJRsm~lwl4I@;CcU}&*^*PD zveJ(Sh$4Ut)(1HndmQd{3WFQ&kOhX6)i2&pH#X6qK8Gq!QzVOT@b$E|`oQjb&8|g- zJ{q4d>@Z{IMj9Bx|LBuaHWRTD5DITp-4%7Kz6?Ga!-PmZThx@MCtb(hfO z;0ln=kPd7&m;wfD0ynelKE1LF6@vBq06nMN86U{ZUW5WJTnGdW{R%6qSt%VQiYVZtybGSgigr%a~ji zw(cny7tJSqTUJVc`dJGQze{HAztP+h_`sx~^Zcpv7<{^MEy~6S2`TW|UV2W47tESSLsF)8+vrRLQdK0AN{-In3GR5aOI;V3uqzZkXF>KDK3k;7B#Me`&6mpl@wJ} zOol_r!G#bY_X>N93)^4TEy9a~BQvytpvBt)#w zr&zfM(HNW0m!m+H6*|eBbH=C#_5o78a3qh-`K+M11I!5^g;%F~BSXWoAp7b2Q8Wf=Lh8KNch4x!M%;cRnw(#@00x z+b-eOX+c{^3{k?#GB=m*lU?Vf*`mmYU4$e-2P^FM9~o-C0qWWqr!=tkHo2LieK&Z1 zRNdF(4tB6%eQBDlT|;K2eN$9^2YPPS>NxjF!@|zZNn>mJx1W}B8H)lc?JTeZxEt$Z z>7KJn?gsyMfgZu(_Z(!Sd?si7gP*`6IrKW33^CsYKO?&EPZ#lKVnWtex4E{q?ve-Y z_Y7841f+5^g`qY|2R^|`B>KfkC4h>QXZt(73KIGOY$Bh+((Px4-=sj^bi^^scuj13 ztozl5Y?Ra014|$&eWzCUnrnb{MX7S~=-ydguWNtoIJ<)c=3*+_#OGRCso(Si+cC$E zS#YiaHQ2R+!!R*j6@0v`Pz6^o#e=md2dP3L^2lg>;(tkmG+wX76w+}YHq$dA#rL7( z8%rB0K$asO(>#M%uusy*bnw6{cQhmyW`J0s=|%GPmuniS;XEW>N7&>H4c}nS5RDcm z7Wy1kB0}T9g+#CAXg;|h^n