From 68810d535b48f52f30d5518156036301dbce1913 Mon Sep 17 00:00:00 2001
From: Saarika Bhasi <55930906+saarikabhasi@users.noreply.github.com>
Date: Tue, 19 Dec 2023 09:48:21 -0500
Subject: [PATCH 01/95] [Serverless Search] Setup FTR tests for Connectors UI
(#173561)
This PR introduces automation tests for Connectors UI for Serverless
Search plugin
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../connector_config/connector_link.tsx | 2 +-
.../connectors/connectors_table.tsx | 10 +-
.../connectors/edit_description.tsx | 8 +-
.../components/connectors/edit_name.tsx | 6 +-
.../connectors/edit_service_type.tsx | 8 +-
.../components/connectors_overview.tsx | 1 +
.../functional/page_objects/index.ts | 2 +
.../svl_search_connectors_page.ts | 160 ++++++++++++++++++
.../search/connectors/connectors_overview.ts | 112 ++++++++++++
.../functional/test_suites/search/index.ts | 1 +
10 files changed, 299 insertions(+), 11 deletions(-)
create mode 100644 x-pack/test_serverless/functional/page_objects/svl_search_connectors_page.ts
create mode 100644 x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts
diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx
index b12f446aa234d..45f43a2b72b35 100644
--- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx
+++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx
@@ -110,7 +110,7 @@ export const ConnectorLinkElasticsearch: React.FCconnector_id
-
+
{connectorId}
diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx
index 2e7e6f2cf6a42..53d99b37c99a1 100644
--- a/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx
+++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connectors_table.tsx
@@ -227,12 +227,17 @@ export const ConnectorsTable: React.FC = () => {
filter ? `${connector[filter]}`.toLowerCase().includes(query.toLowerCase()) : true
)
.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize) ?? [];
-
return (
<>
- setQuery(queryText ?? '')} query={query} />
+ setQuery(queryText ?? '')}
+ query={query}
+ />
{
= ({ connector }) =
value={newDescription || ''}
/>
) : (
- {connector.description}
+
+ {connector.description}
+
)}
@@ -107,7 +109,7 @@ export const EditDescription: React.FC = ({ connector }) =
`}
>
mutate(newDescription)}
@@ -125,7 +127,7 @@ export const EditDescription: React.FC = ({ connector }) =
`}
>
{
diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx
index e8073796c7c9c..fbab2b15d3434 100644
--- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx
+++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_name.tsx
@@ -69,7 +69,7 @@ export const EditName: React.FC = ({ connector }) => {
{!isEditing ? (
<>
-
+
{connector.name || CONNECTOR_LABEL}
@@ -113,7 +113,7 @@ export const EditName: React.FC = ({ connector }) => {
`}
>
= ({ connector }) => {
`}
>
{
diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx
index c3e7c3f8455ba..a2df8f7c35bfe 100644
--- a/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx
+++ b/x-pack/plugins/serverless_search/public/application/components/connectors/edit_service_type.tsx
@@ -37,7 +37,10 @@ export const EditServiceType: React.FC = ({ connector }) =
connectorTypes?.connectors.map((connectorType) => ({
inputDisplay: (
-
+
= ({ connector }) =
return (
-
+
{i18n.translate('xpack.serverlessSearch.connectors.serviceTypeLabel', {
defaultMessage: 'Connector type',
})}
mutate(event)}
options={options}
diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx
index fd774f3dd4911..78c70321d178c 100644
--- a/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx
+++ b/x-pack/plugins/serverless_search/public/application/components/connectors_overview.tsx
@@ -38,6 +38,7 @@ export const ConnectorsOverview = () => {
pageTitle={i18n.translate('xpack.serverlessSearch.connectors.title', {
defaultMessage: 'Connectors',
})}
+ data-test-subj="serverlessSearchConnectorsTitle"
restrictWidth
rightSideItems={[
diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts
index f9626a88b3103..541c7dce86cec 100644
--- a/x-pack/test_serverless/functional/page_objects/index.ts
+++ b/x-pack/test_serverless/functional/page_objects/index.ts
@@ -18,6 +18,7 @@ import { SvlSearchLandingPageProvider } from './svl_search_landing_page';
import { SvlSecLandingPageProvider } from './svl_sec_landing_page';
import { SvlTriggersActionsPageProvider } from './svl_triggers_actions_ui_page';
import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page';
+import { SvlSearchConnectorsPageProvider } from './svl_search_connectors_page';
export const pageObjects = {
...xpackFunctionalPageObjects,
@@ -28,6 +29,7 @@ export const pageObjects = {
svlObltOnboardingPage: SvlObltOnboardingPageProvider,
SvlObltOnboardingStreamLogFilePage: SvlObltOnboardingStreamLogFilePageProvider,
svlObltOverviewPage: SvlObltOverviewPageProvider,
+ svlSearchConnectorsPage: SvlSearchConnectorsPageProvider,
svlSearchLandingPage: SvlSearchLandingPageProvider,
svlSecLandingPage: SvlSecLandingPageProvider,
svlTriggersActionsUI: SvlTriggersActionsPageProvider,
diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_connectors_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_connectors_page.ts
new file mode 100644
index 0000000000000..f610251bf0719
--- /dev/null
+++ b/x-pack/test_serverless/functional/page_objects/svl_search_connectors_page.ts
@@ -0,0 +1,160 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor 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 { FtrProviderContext } from '../ftr_provider_context';
+export function SvlSearchConnectorsPageProvider({ getService }: FtrProviderContext) {
+ const testSubjects = getService('testSubjects');
+ const browser = getService('browser');
+ const retry = getService('retry');
+ return {
+ connectorConfigurationPage: {
+ async createConnector() {
+ await testSubjects.click('serverlessSearchConnectorsOverviewCreateConnectorButton');
+ await testSubjects.existOrFail('serverlessSearchEditConnectorButton');
+ await testSubjects.exists('serverlessSearchConnectorLinkElasticsearchRunWithDockerButton');
+ await testSubjects.exists('serverlessSearchConnectorLinkElasticsearchRunFromSourceButton');
+ },
+ async editDescription(description: string) {
+ await testSubjects.existOrFail('serverlessSearchEditDescriptionButton');
+ await testSubjects.click('serverlessSearchEditDescriptionButton');
+ await testSubjects.exists('serverlessSearchEditDescriptionFieldText');
+ await testSubjects.existOrFail('serverlessSearchSaveDescriptionButton');
+ await testSubjects.existOrFail('serverlessSearchCancelDescriptionButton');
+ await testSubjects.setValue('serverlessSearchEditDescriptionFieldText', description);
+ await testSubjects.click('serverlessSearchSaveDescriptionButton');
+ await testSubjects.exists('serverlessSearchConnectorDescription');
+ expect(await testSubjects.getVisibleText('serverlessSearchConnectorDescription')).to.be(
+ description
+ );
+ },
+ async editName(name: string) {
+ await testSubjects.existOrFail('serverlessSearchEditNameButton');
+ await testSubjects.click('serverlessSearchEditNameButton');
+ await testSubjects.existOrFail('serverlessSearchEditNameFieldText');
+ await testSubjects.existOrFail('serverlessSearchSaveNameButton');
+ await testSubjects.existOrFail('serverlessSearchCancelNameButton');
+ await testSubjects.setValue('serverlessSearchEditNameFieldText', name);
+ await testSubjects.click('serverlessSearchSaveNameButton');
+ await testSubjects.exists('serverlessSearchConnectorName');
+ expect(await testSubjects.getVisibleText('serverlessSearchConnectorName')).to.be(name);
+ },
+ async editType(type: string) {
+ await testSubjects.existOrFail('serverlessSearchEditConnectorTypeLabel');
+ await testSubjects.existOrFail('serverlessSearchEditConnectorTypeChoices');
+ await testSubjects.click('serverlessSearchEditConnectorTypeChoices');
+ await testSubjects.exists('serverlessSearchConnectorServiceType-zoom');
+ await testSubjects.click(`serverlessSearchConnectorServiceType-${type}`);
+ await testSubjects.existOrFail('serverlessSearchConnectorServiceType-zoom');
+ },
+ async expectConnectorIdToMatchUrl(connectorId: string) {
+ expect(await browser.getCurrentUrl()).contain(`/app/connectors/${connectorId}`);
+ },
+ async getConnectorId() {
+ return await testSubjects.getVisibleText('serverlessSearchConnectorConnectorId');
+ },
+ },
+ connectorOverviewPage: {
+ async changeSearchBarTableSelectValue(option: string) {
+ await testSubjects.existOrFail('serverlessSearchConnectorsTableSelect');
+ await testSubjects.setValue('serverlessSearchConnectorsTableSelect', option);
+ },
+ async connectorNameExists(connectorName: string) {
+ const connectorsList = await this.getConnectorsList();
+ return Boolean(connectorsList.find((name) => name === connectorName));
+ },
+ async confirmDeleteConnectorModalComponentsExists() {
+ await testSubjects.existOrFail('serverlessSearchDeleteConnectorModalFieldText');
+ await testSubjects.existOrFail('confirmModalConfirmButton');
+ await testSubjects.existOrFail('confirmModalCancelButton');
+ },
+ async confirmConnectorTableIsDisappearedAfterDelete() {
+ await retry.waitForWithTimeout('delete modal to disappear', 5000, () =>
+ testSubjects
+ .missingOrFail('confirmModalConfirmButton')
+ .then(() => true)
+ .catch(() => false)
+ );
+ browser.refresh();
+ this.expectConnectorTableToHaveNoItems();
+ },
+ async expectConnectorOverviewPageComponentsToExist() {
+ await testSubjects.existOrFail('serverlessSearchConnectorsTitle');
+ await testSubjects.existOrFail('serverlessSearchConnectorsOverviewElasticConnectorsLink');
+ await testSubjects.exists('serverlessSearchEmptyConnectorsPromptCreateConnectorButton');
+ await testSubjects.existOrFail('serverlessSearchConnectorsOverviewCreateConnectorButton');
+ },
+ async expectConnectorTableToExist() {
+ await testSubjects.existOrFail('serverlessSearchConnectorTable');
+ },
+ async expectConnectorTableToHaveNoItems(timeout?: number) {
+ await testSubjects.missingOrFail('serverlessSearchColumnsLink', { timeout });
+ },
+ async expectDeleteConnectorButtonExist() {
+ await testSubjects.existOrFail('serverlessSearchDeleteConnectorModalActionButton');
+ },
+ async expectSearchBarToExist() {
+ await testSubjects.existOrFail('serverlessSearchConnectorsTableSearchBar');
+ },
+
+ async deleteConnectorWithCorrectName(connectorNameToBeDeleted: string) {
+ const fieldText = await testSubjects.find('serverlessSearchDeleteConnectorModalFieldText');
+ await fieldText.clearValue();
+ await retry.try(async () => {
+ expect(
+ await (
+ await testSubjects.find('serverlessSearchDeleteConnectorModalFieldText')
+ ).getAttribute('value')
+ ).to.be('');
+ });
+ await retry.try(async () => {
+ await fieldText.type(connectorNameToBeDeleted);
+ });
+ const isEnabled = await testSubjects.isEnabled('confirmModalConfirmButton');
+ expect(isEnabled).to.be(true);
+ await retry.try(async () => await testSubjects.click('confirmModalConfirmButton'));
+ },
+ async deleteConnectorIncorrectName(incorrectName: string) {
+ const fieldText = await testSubjects.find('serverlessSearchDeleteConnectorModalFieldText');
+ await fieldText.clearValue();
+ await retry.try(async () => {
+ await fieldText.type(incorrectName);
+ });
+ const isEnabled = await testSubjects.isEnabled('confirmModalConfirmButton');
+ expect(isEnabled).to.be(false);
+ },
+ async getConnectorFromConnectorTable(connectorName: string) {
+ await testSubjects.getAttribute('serverlessSearchColumnsLink', connectorName);
+ },
+ async getConnectorsList() {
+ const rows = await (
+ await testSubjects.find('serverlessSearchConnectorTable')
+ ).findAllByCssSelector('.euiTableRow');
+ return await Promise.all(
+ rows.map(async (connector) => {
+ return await (
+ await connector.findByTestSubject('serverlessSearchColumnsLink')
+ ).getVisibleText();
+ })
+ );
+ },
+ async openDeleteConnectorModal() {
+ await retry.try(
+ async () => await testSubjects.click('serverlessSearchDeleteConnectorModalActionButton')
+ );
+ await testSubjects.exists('confirmModalBodyText');
+ expect(await testSubjects.getVisibleText('confirmModalBodyText')).to.be(
+ 'This action cannot be undone. Please type my-connector to confirm.\nConnector name'
+ );
+ },
+ async setSearchBarValue(value: string) {
+ await testSubjects.setValue('serverlessSearchConnectorsTableSearchBar', value);
+ await testSubjects.pressEnter('serverlessSearchConnectorsTableSearchBar');
+ },
+ },
+ };
+}
diff --git a/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts b/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts
new file mode 100644
index 0000000000000..d5fedb8c54585
--- /dev/null
+++ b/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.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 { FtrProviderContext } from '../../../ftr_provider_context';
+const TEST_CONNECTOR_NAME = 'my-connector';
+export default function ({ getPageObjects, getService }: FtrProviderContext) {
+ const pageObjects = getPageObjects([
+ 'svlCommonPage',
+ 'svlCommonNavigation',
+ 'common',
+ 'svlSearchConnectorsPage',
+ ]);
+ const testSubjects = getService('testSubjects');
+ const browser = getService('browser');
+ describe('connectors', function () {
+ before(async () => {
+ await pageObjects.svlCommonPage.login();
+ await pageObjects.svlCommonNavigation.sidenav.clickLink({
+ deepLinkId: 'serverlessConnectors',
+ });
+ });
+
+ after(async () => {
+ await pageObjects.svlCommonPage.forceLogout();
+ });
+
+ it('Connector app is loaded and has no connectors', async () => {
+ await pageObjects.svlSearchConnectorsPage.connectorOverviewPage.expectConnectorOverviewPageComponentsToExist();
+ });
+ describe('create and configure connector', async () => {
+ it('create connector and confirm connector configuration page is loaded', async () => {
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.createConnector();
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.expectConnectorIdToMatchUrl(
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.getConnectorId()
+ );
+ });
+ it('edit description', async () => {
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.editDescription(
+ 'test description'
+ );
+ });
+ it('edit name', async () => {
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.editName(
+ TEST_CONNECTOR_NAME
+ );
+ });
+ it('edit type', async () => {
+ await pageObjects.svlSearchConnectorsPage.connectorConfigurationPage.editType('zoom');
+ });
+ it('confirm connector is created', async () => {
+ await pageObjects.svlCommonNavigation.sidenav.clickLink({
+ deepLinkId: 'serverlessConnectors',
+ });
+ browser.refresh();
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.expectConnectorTableToExist();
+ });
+ });
+ describe('connector table', async () => {
+ it('confirm searchBar to exist', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.expectSearchBarToExist();
+ });
+
+ it('searchBar and select filter connector table', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.getConnectorFromConnectorTable(
+ TEST_CONNECTOR_NAME
+ );
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.setSearchBarValue(
+ TEST_CONNECTOR_NAME
+ );
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.connectorNameExists(
+ TEST_CONNECTOR_NAME
+ );
+
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.changeSearchBarTableSelectValue(
+ 'Type'
+ );
+
+ await testSubjects.click('clearSearchButton');
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.setSearchBarValue('confluence');
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.expectConnectorTableToHaveNoItems();
+ await testSubjects.click('clearSearchButton');
+ });
+ });
+ describe('delete connector', async () => {
+ it('delete connector button exist in table', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.expectDeleteConnectorButtonExist();
+ });
+ it('open delete connector modal', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.openDeleteConnectorModal();
+ });
+ it('delete connector button open modal', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.confirmDeleteConnectorModalComponentsExists();
+ });
+ it('delete connector field is disabled if field name does not match connector name', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.deleteConnectorIncorrectName(
+ 'invalid'
+ );
+ });
+ it('delete connector button deletes connector', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.deleteConnectorWithCorrectName(
+ TEST_CONNECTOR_NAME
+ );
+ });
+ it('confirm connector table is disappeared after delete ', async () => {
+ pageObjects.svlSearchConnectorsPage.connectorOverviewPage.confirmConnectorTableIsDisappearedAfterDelete();
+ });
+ });
+ });
+}
diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts
index 6d0987d0292ce..8b753e58005fa 100644
--- a/x-pack/test_serverless/functional/test_suites/search/index.ts
+++ b/x-pack/test_serverless/functional/test_suites/search/index.ts
@@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('serverless search UI', function () {
loadTestFile(require.resolve('./landing_page'));
+ loadTestFile(require.resolve('./connectors/connectors_overview'));
loadTestFile(require.resolve('./default_dataview'));
loadTestFile(require.resolve('./navigation'));
loadTestFile(require.resolve('./cases/attachment_framework'));
From 64bd042a21c34f95145c6117c87760134637a657 Mon Sep 17 00:00:00 2001
From: Liam Thompson <32779855+leemthompo@users.noreply.github.com>
Date: Tue, 19 Dec 2023 15:48:40 +0100
Subject: [PATCH 02/95] [Enterprise Search] Clean up copy (#173622)
Somehow this copy snuck in without being edited, looks like a copy paste
from a former tooltip or something, with no punctuation.
This PR cleans the text up.
## Before
---
.../new_index/select_connector/select_connector.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/select_connector/select_connector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/select_connector/select_connector.tsx
index 31c4f9cc7a71b..8c75fa9a4b1b6 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/select_connector/select_connector.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/select_connector/select_connector.tsx
@@ -225,7 +225,7 @@ export const SelectConnector: React.FC = () => {
'xpack.enterpriseSearch.selectConnector.p.areAvailableDirectlyWithinLabel',
{
defaultMessage:
- 'Are available directly within Elastic Cloud deployments No additional infrastructure is required You can also convert them as self hosted Connectors client at any moment',
+ 'Available directly within Elastic Cloud deployments. No additional infrastructure is required. You can also convert native connectors to self-hosted connector clients.',
}
)}
@@ -259,7 +259,7 @@ export const SelectConnector: React.FC = () => {
'xpack.enterpriseSearch.selectConnector.p.deployConnectorsOnYourLabel',
{
defaultMessage:
- 'Deploy connectors on your own infrastructure You can also customize existing Connector clients or build your own using our connector framework',
+ 'Deploy connectors on your own infrastructure. You can also customize existing connector clients, or build your own using our connector framework.',
}
)}
From b9d3c8611876632c587ca854125315c6a5c303bb Mon Sep 17 00:00:00 2001
From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com>
Date: Tue, 19 Dec 2023 16:07:25 +0100
Subject: [PATCH 03/95] [Fleet] show download rate in upgrade details tooltlip
(#173614)
## Summary
Closes https://github.com/elastic/kibana/issues/171943
Showing download rate in the upgrade details tooltip.
Used fake data as I couldn't get an actual agent to be in downloading
state with download percent and rate.
Insert test ES data with curl and go to Agent list/details to see the
tooltip, replace `existing_agent_id` with an existing agent's id or
insert a full agent doc.
```
curl -sk -XPOST --user elastic:changeme -H 'content-type:application/json' \
http://localhost:9200/_security/role/fleet_superuser -d '
{
"indices": [
{
"names": [".fleet*",".kibana*"],
"privileges": ["all"],
"allow_restricted_indices": true
}
]
}'
curl -sk -XPOST --user elastic:changeme -H 'content-type:application/json' \
http://localhost:9200/_security/user/fleet_superuser -d '
{
"password": "password",
"roles": ["superuser", "fleet_superuser"]
}'
curl -sk -XPOST --user fleet_superuser:password -H 'content-type:application/json' \
-H'x-elastic-product-origin:fleet' \
http://localhost:9200/.fleet-agents/_update_by_query -d '
{
"script": {
"source": "ctx._source.upgrade_details.state = \"UPG_DOWNLOADING\"; ctx._source.upgrade_details.metadata.download_percent = 22; ctx._source.upgrade_details.metadata.download_rate = 1223912;",
"lang": "painless"
},
"query": {
"term": {
"agent.id":"existing_agent_id"
}
}
}'
```
### 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
---
.../fleet/common/types/models/agent.ts | 1 +
.../components/agent_upgrade_status.test.tsx | 32 +++++++++++++++++--
.../components/agent_upgrade_status.tsx | 30 +++++++++++++----
3 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/x-pack/plugins/fleet/common/types/models/agent.ts b/x-pack/plugins/fleet/common/types/models/agent.ts
index 120f0bc883e1d..1242a61124952 100644
--- a/x-pack/plugins/fleet/common/types/models/agent.ts
+++ b/x-pack/plugins/fleet/common/types/models/agent.ts
@@ -446,6 +446,7 @@ export interface AgentUpgradeDetails {
metadata?: {
scheduled_at?: string;
download_percent?: number;
+ download_rate?: number; // bytes per second
failed_state?: AgentUpgradeStateType;
error_msg?: string;
};
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
index 1518a68fd6f0c..a5f3498fd0b59 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.test.tsx
@@ -48,12 +48,38 @@ describe('getDownloadEstimate', () => {
expect(getDownloadEstimate()).toEqual('');
});
- it('should return an empty string if the agent has a zero download percent', () => {
- expect(getDownloadEstimate(0)).toEqual('');
+ it('should display 0% if the agent has a zero download percent', () => {
+ expect(getDownloadEstimate({ download_percent: 0 })).toEqual(' (0%)');
+ });
+
+ it('should display 0 Bps if the agent has a zero download rate', () => {
+ expect(getDownloadEstimate({ download_rate: 0 })).toEqual(' (at 0.0 Bps)');
});
it('should return a formatted string if the agent has a positive download percent', () => {
- expect(getDownloadEstimate(16.4)).toEqual(' (16.4%)');
+ expect(getDownloadEstimate({ download_percent: 16.4 })).toEqual(' (16.4%)');
+ });
+
+ it('should return a formatted string if the agent has a kBps download rate', () => {
+ expect(getDownloadEstimate({ download_rate: 1024 })).toEqual(' (at 1.0 kBps)');
+ });
+
+ it('should return a formatted string if the agent has a download rate and download percent', () => {
+ expect(getDownloadEstimate({ download_rate: 10, download_percent: 99 })).toEqual(
+ ' (99% at 10.0 Bps)'
+ );
+ });
+
+ it('should return a formatted string if the agent has a MBps download rate', () => {
+ expect(getDownloadEstimate({ download_rate: 1200000 })).toEqual(' (at 1.1 MBps)');
+ });
+
+ it('should return a formatted string if the agent has a GBps download rate', () => {
+ expect(getDownloadEstimate({ download_rate: 2400000000 })).toEqual(' (at 2.2 GBps)');
+ });
+
+ it('should return a formatted string if the agent has a GBps download rate more than 1024', () => {
+ expect(getDownloadEstimate({ download_rate: 1200000000 * 1024 })).toEqual(' (at 1144.4 GBps)');
});
});
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx
index 203b490f9f3ef..e5cf2eb7913c6 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_upgrade_status.tsx
@@ -35,14 +35,34 @@ export function getUpgradeStartDelay(scheduledAt?: string): string {
return ` The upgrade will start in less than ${Math.ceil(timeDiffMillis / 36e5)} hours.`;
}
-export function getDownloadEstimate(downloadPercent?: number): string {
- if (!downloadPercent || downloadPercent === 0) {
+export function getDownloadEstimate(metadata?: AgentUpgradeDetails['metadata']): string {
+ if (
+ !metadata ||
+ (metadata.download_percent === undefined && metadata.download_rate === undefined)
+ ) {
return '';
}
+ let tooltip = '';
+ if (metadata.download_percent !== undefined) {
+ tooltip = `${metadata.download_percent}%`;
+ }
+ if (metadata.download_rate !== undefined) {
+ tooltip += ` at ${formatRate(metadata.download_rate)}`;
+ }
- return ` (${downloadPercent}%)`;
+ return ` (${tooltip.trim()})`;
}
+const formatRate = (downloadRate: number) => {
+ let i = 0;
+ const byteUnits = [' Bps', ' kBps', ' MBps', ' GBps'];
+ for (; i < byteUnits.length - 1; i++) {
+ if (downloadRate < 1024) break;
+ downloadRate = downloadRate / 1024;
+ }
+ return downloadRate.toFixed(1) + byteUnits[i];
+};
+
function getStatusComponents(agentUpgradeDetails?: AgentUpgradeDetails) {
switch (agentUpgradeDetails?.state) {
case 'UPG_REQUESTED':
@@ -97,9 +117,7 @@ function getStatusComponents(agentUpgradeDetails?: AgentUpgradeDetails) {
id="xpack.fleet.agentUpgradeStatusTooltip.upgradeDownloading"
defaultMessage="Downloading the new agent artifact version{downloadEstimate}."
values={{
- downloadEstimate: getDownloadEstimate(
- agentUpgradeDetails?.metadata?.download_percent
- ),
+ downloadEstimate: getDownloadEstimate(agentUpgradeDetails?.metadata),
}}
/>
),
From b1457d0cb10c0884220573ac84d7e79c36780aeb Mon Sep 17 00:00:00 2001
From: Panagiota Mitsopoulou
Date: Tue, 19 Dec 2023 16:16:09 +0100
Subject: [PATCH 04/95] attach slo card to dashboard (#172670)
Fixes https://github.com/elastic/kibana/issues/171349
https://github.com/elastic/kibana/assets/2852703/f951885a-e0f3-4f12-bfa0-fe5e354c9285
---------
Co-authored-by: shahzad31
---
x-pack/plugins/observability/kibana.jsonc | 4 +-
.../public/application/index.tsx | 85 ++++++++++---------
.../components/card_view/slo_card_item.tsx | 42 +++++++--
.../card_view/slo_card_item_actions.tsx | 1 +
.../slos/components/slo_item_actions.tsx | 19 +++++
.../pages/slos/components/slo_list_item.tsx | 1 +
.../pages/slos/hooks/use_slo_list_actions.ts | 33 +++++++
x-pack/plugins/observability/public/plugin.ts | 3 +
x-pack/plugins/observability/tsconfig.json | 1 +
9 files changed, 139 insertions(+), 50 deletions(-)
diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc
index 690fd21462128..d5633ad9f36fe 100644
--- a/x-pack/plugins/observability/kibana.jsonc
+++ b/x-pack/plugins/observability/kibana.jsonc
@@ -21,6 +21,7 @@
"dataViewEditor",
"embeddable",
"uiActions",
+ "presentationUtil",
"exploratoryView",
"features",
"files",
@@ -55,7 +56,8 @@
"kibanaUtils",
"unifiedSearch",
"stackAlerts",
- "spaces"
+ "spaces",
+ "embeddable"
],
"extraPublicDirs": [
"common"
diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx
index 7081005487fc3..7b01bc1f8eeb1 100644
--- a/x-pack/plugins/observability/public/application/index.tsx
+++ b/x-pack/plugins/observability/public/application/index.tsx
@@ -84,51 +84,54 @@ export const renderApp = ({
const ApplicationUsageTrackingProvider =
usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment;
const CloudProvider = plugins.cloud?.CloudContextProvider ?? React.Fragment;
+ const PresentationContextProvider = plugins.presentationUtil?.ContextProvider ?? React.Fragment;
ReactDOM.render(
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
element
);
return () => {
diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx
index 04a23c296a602..ccdfe39481558 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item.tsx
@@ -20,6 +20,10 @@ import { ALL_VALUE, HistoricalSummaryResponse, SLOWithSummaryResponse } from '@k
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
import { i18n } from '@kbn/i18n';
import { css } from '@emotion/react';
+import {
+ LazySavedObjectSaveModalDashboard,
+ withSuspense,
+} from '@kbn/presentation-util-plugin/public';
import { SloCardBadgesPortal } from './badges_portal';
import { useSloListActions } from '../../hooks/use_slo_list_actions';
import { BurnRateRuleFlyout } from '../common/burn_rate_rule_flyout';
@@ -30,7 +34,7 @@ import { SloCardItemActions } from './slo_card_item_actions';
import { SloRule } from '../../../../hooks/slo/use_fetch_rules_for_slo';
import { SloDeleteConfirmationModal } from '../../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal';
import { SloCardItemBadges } from './slo_card_item_badges';
-
+const SavedObjectSaveModalDashboard = withSuspense(LazySavedObjectSaveModalDashboard);
export interface Props {
slo: SLOWithSummaryResponse;
rules: Array> | undefined;
@@ -64,15 +68,17 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false);
const [isAddRuleFlyoutOpen, setIsAddRuleFlyoutOpen] = useState(false);
const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false);
-
+ const [isDashboardAttachmentReady, setDashboardAttachmentReady] = useState(false);
const historicalSliData = formatHistoricalData(historicalSummary, 'sli_value');
- const { handleCreateRule, handleDeleteCancel, handleDeleteConfirm } = useSloListActions({
- slo,
- setDeleteConfirmationModalOpen,
- setIsActionsPopoverOpen,
- setIsAddRuleFlyoutOpen,
- });
+ const { handleCreateRule, handleDeleteCancel, handleDeleteConfirm, handleAttachToDashboardSave } =
+ useSloListActions({
+ slo,
+ setDeleteConfirmationModalOpen,
+ setIsActionsPopoverOpen,
+ setIsAddRuleFlyoutOpen,
+ setDashboardAttachmentReady,
+ });
return (
<>
@@ -104,6 +110,7 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
setIsActionsPopoverOpen={setIsActionsPopoverOpen}
setIsAddRuleFlyoutOpen={setIsAddRuleFlyoutOpen}
setDeleteConfirmationModalOpen={setDeleteConfirmationModalOpen}
+ setDashboardAttachmentReady={setDashboardAttachmentReady}
/>
)}
@@ -130,6 +137,25 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards
onConfirm={handleDeleteConfirm}
/>
) : null}
+ {isDashboardAttachmentReady ? (
+ {
+ setDashboardAttachmentReady(false);
+ }}
+ onSave={handleAttachToDashboardSave}
+ />
+ ) : null}
>
);
}
diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx
index 51d1887d433fb..ff4d7f363caee 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slo_card_item_actions.tsx
@@ -41,6 +41,7 @@ interface Props {
setIsActionsPopoverOpen: (value: boolean) => void;
setDeleteConfirmationModalOpen: (value: boolean) => void;
setIsAddRuleFlyoutOpen: (value: boolean) => void;
+ setDashboardAttachmentReady: (value: boolean) => void;
}
export function SloCardItemActions(props: Props) {
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx
index 51652abe13542..8bda3b98bd510 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx
@@ -30,6 +30,7 @@ interface Props {
setIsActionsPopoverOpen: (value: boolean) => void;
setDeleteConfirmationModalOpen: (value: boolean) => void;
setIsAddRuleFlyoutOpen: (value: boolean) => void;
+ setDashboardAttachmentReady?: (value: boolean) => void;
btnProps?: Partial;
}
const CustomShadowPanel = styled(EuiPanel)<{ shadow: string }>`
@@ -59,6 +60,7 @@ export function SloItemActions({
setIsActionsPopoverOpen,
setIsAddRuleFlyoutOpen,
setDeleteConfirmationModalOpen,
+ setDashboardAttachmentReady,
btnProps,
}: Props) {
const {
@@ -110,6 +112,13 @@ export function SloItemActions({
setIsAddRuleFlyoutOpen(true);
};
+ const handleAttachToDashboard = () => {
+ setIsActionsPopoverOpen(false);
+ if (setDashboardAttachmentReady) {
+ setDashboardAttachmentReady(true);
+ }
+ };
+
const btn = (
,
+
+ {i18n.translate('xpack.observability.slo.item.actions.attachToDashboard', {
+ defaultMessage: 'Attach to Dashboard',
+ })}
+ ,
]}
/>
diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
index 31455cea01905..dc3865af00050 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/slo_list_item.tsx
@@ -9,6 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui';
import { HistoricalSummaryResponse, SLOWithSummaryResponse } from '@kbn/slo-schema';
import type { Rule } from '@kbn/triggers-actions-ui-plugin/public';
import React, { useState } from 'react';
+
import { SloDeleteConfirmationModal } from '../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal';
import { useSloFormattedSummary } from '../hooks/use_slo_summary';
import { BurnRateRuleFlyout } from './common/burn_rate_rule_flyout';
diff --git a/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts
index 169e1e54c5222..bdc6cf3a4c49d 100644
--- a/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts
+++ b/x-pack/plugins/observability/public/pages/slos/hooks/use_slo_list_actions.ts
@@ -6,19 +6,26 @@
*/
import { SLOWithSummaryResponse } from '@kbn/slo-schema';
+import { SaveModalDashboardProps } from '@kbn/presentation-util-plugin/public';
+import { useCallback } from 'react';
import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo';
+import { SLO_EMBEDDABLE } from '../../../embeddable/slo/overview/slo_embeddable';
+import { useKibana } from '../../../utils/kibana_react';
export function useSloListActions({
slo,
setIsAddRuleFlyoutOpen,
setIsActionsPopoverOpen,
setDeleteConfirmationModalOpen,
+ setDashboardAttachmentReady,
}: {
slo: SLOWithSummaryResponse;
setIsActionsPopoverOpen: (val: boolean) => void;
setIsAddRuleFlyoutOpen: (val: boolean) => void;
setDeleteConfirmationModalOpen: (val: boolean) => void;
+ setDashboardAttachmentReady?: (val: boolean) => void;
}) {
+ const { embeddable } = useKibana().services;
const { mutate: deleteSlo } = useDeleteSlo();
const handleDeleteConfirm = () => {
@@ -34,9 +41,35 @@ export function useSloListActions({
setIsAddRuleFlyoutOpen(true);
};
+ const handleAttachToDashboardSave: SaveModalDashboardProps['onSave'] = useCallback(
+ ({ dashboardId, newTitle, newDescription }) => {
+ const stateTransfer = embeddable!.getStateTransfer();
+ const embeddableInput = {
+ title: newTitle,
+ description: newDescription,
+ sloId: slo.id,
+ sloInstanceId: slo.instanceId,
+ };
+
+ const state = {
+ input: embeddableInput,
+ type: SLO_EMBEDDABLE,
+ };
+
+ const path = dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`;
+
+ stateTransfer.navigateToWithEmbeddablePackage('dashboards', {
+ state,
+ path,
+ });
+ },
+ [embeddable, slo.id, slo.instanceId]
+ );
+
return {
handleDeleteConfirm,
handleDeleteCancel,
handleCreateRule,
+ handleAttachToDashboardSave,
};
}
diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts
index 2e716f42d0713..808573579cb99 100644
--- a/x-pack/plugins/observability/public/plugin.ts
+++ b/x-pack/plugins/observability/public/plugin.ts
@@ -67,6 +67,7 @@ import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/pu
import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public';
import { firstValueFrom } from 'rxjs';
+import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
import { observabilityAppId, observabilityFeatureId } from '../common';
import {
ALERTS_PATH,
@@ -123,6 +124,7 @@ export interface ObservabilityPublicPluginsSetup {
uiActions: UiActionsSetup;
licensing: LicensingPluginSetup;
serverless?: ServerlessPluginSetup;
+ presentationUtil?: PresentationUtilPluginStart;
}
export interface ObservabilityPublicPluginsStart {
actionTypeRegistry: ActionTypeRegistryContract;
@@ -153,6 +155,7 @@ export interface ObservabilityPublicPluginsStart {
serverless?: ServerlessPluginStart;
uiSettings: IUiSettingsClient;
uiActions: UiActionsStart;
+ presentationUtil?: PresentationUtilPluginStart;
}
export type ObservabilityPublicStart = ReturnType;
diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json
index 6cc8bbfef132f..61762322f9eed 100644
--- a/x-pack/plugins/observability/tsconfig.json
+++ b/x-pack/plugins/observability/tsconfig.json
@@ -97,6 +97,7 @@
"@kbn/serverless",
"@kbn/dashboard-plugin",
"@kbn/calculate-auto",
+ "@kbn/presentation-util-plugin",
"@kbn/task-manager-plugin",
"@kbn/core-elasticsearch-client-server-mocks",
"@kbn/core-saved-objects-api-server-mocks"
From 86561c2ace1924abb1d36c0c7abfd16b46a135c8 Mon Sep 17 00:00:00 2001
From: Shahzad
Date: Tue, 19 Dec 2023 16:20:37 +0100
Subject: [PATCH 05/95] [UX INP] Fix label casing (#173605)
## Summary
Fix label casing !!
---
.../components/sections/ux/core_web_vitals/translations.ts | 2 +-
x-pack/plugins/ux/e2e/journeys/inp.journey.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/observability/public/pages/overview/components/sections/ux/core_web_vitals/translations.ts b/x-pack/plugins/observability/public/pages/overview/components/sections/ux/core_web_vitals/translations.ts
index d6445320a7978..bded2fd67cca8 100644
--- a/x-pack/plugins/observability/public/pages/overview/components/sections/ux/core_web_vitals/translations.ts
+++ b/x-pack/plugins/observability/public/pages/overview/components/sections/ux/core_web_vitals/translations.ts
@@ -16,7 +16,7 @@ export const LCP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.lcp',
});
export const INP_LABEL = i18n.translate('xpack.observability.ux.coreVitals.inp', {
- defaultMessage: 'Interaction to Next Paint',
+ defaultMessage: 'Interaction to next paint',
});
export const CLS_LABEL = i18n.translate('xpack.observability.ux.coreVitals.cls', {
diff --git a/x-pack/plugins/ux/e2e/journeys/inp.journey.ts b/x-pack/plugins/ux/e2e/journeys/inp.journey.ts
index 800ae3e38b3fd..8422dacf03781 100644
--- a/x-pack/plugins/ux/e2e/journeys/inp.journey.ts
+++ b/x-pack/plugins/ux/e2e/journeys/inp.journey.ts
@@ -59,7 +59,7 @@ journey('INP', async ({ page, params }) => {
});
step('Check INP Values', async () => {
- expect(await page.$('text=Interaction to Next Paint'));
+ expect(await page.$('text=Interaction to next paint'));
await page.waitForSelector('[data-test-subj=inp-core-vital] > .euiTitle');
await page.waitForSelector('text=381 ms');
});
From d79f191b4e12a1ae7634c1a1f5e676aeec499b93 Mon Sep 17 00:00:00 2001
From: Lukas Olson
Date: Tue, 19 Dec 2023 08:28:17 -0700
Subject: [PATCH 06/95] [Discover] Include column width in shared links
(#172405)
## Summary
Resolves https://github.com/elastic/kibana/issues/170577.
Includes the `grid` properties (which include specified column widths)
in the shareable links generated from Discover.
### 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
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
### Release note
Discover sharing links now preserve customized column widths.
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
---
src/plugins/discover/common/locator.test.ts | 9 +++++++--
src/plugins/discover/common/locator.ts | 9 +++++++++
.../main/components/top_nav/get_top_nav_links.tsx | 3 +--
.../main/services/discover_app_state_container.ts | 4 ++--
.../application/main/services/discover_state.ts | 1 +
src/plugins/saved_search/common/types.ts | 13 +++++--------
src/plugins/saved_search/tsconfig.json | 1 +
7 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/src/plugins/discover/common/locator.test.ts b/src/plugins/discover/common/locator.test.ts
index 80bc4ceebed2b..93da54ad365e9 100644
--- a/src/plugins/discover/common/locator.test.ts
+++ b/src/plugins/discover/common/locator.test.ts
@@ -218,17 +218,22 @@ describe('Discover url generator', () => {
expect(path).toContain('__test__');
});
- test('can specify columns, interval, sort and savedQuery', async () => {
+ test('can specify columns, grid, interval, sort and savedQuery', async () => {
const { locator } = await setup();
const { path } = await locator.getLocation({
columns: ['_source'],
+ grid: {
+ columns: {
+ _source: { width: 150 },
+ },
+ },
interval: 'auto',
sort: [['timestamp, asc']] as string[][] & SerializableRecord,
savedQuery: '__savedQueryId__',
});
expect(path).toMatchInlineSnapshot(
- `"#/?_a=(columns:!(_source),interval:auto,savedQuery:__savedQueryId__,sort:!(!('timestamp,%20asc')))"`
+ `"#/?_a=(columns:!(_source),grid:(columns:(_source:(width:150))),interval:auto,savedQuery:__savedQueryId__,sort:!(!('timestamp,%20asc')))"`
);
});
diff --git a/src/plugins/discover/common/locator.ts b/src/plugins/discover/common/locator.ts
index 70e60f55b5fb1..9be9947e743dd 100644
--- a/src/plugins/discover/common/locator.ts
+++ b/src/plugins/discover/common/locator.ts
@@ -10,6 +10,7 @@ import type { SerializableRecord } from '@kbn/utility-types';
import type { Filter, TimeRange, Query, AggregateQuery } from '@kbn/es-query';
import type { GlobalQueryStateFromUrl, RefreshInterval } from '@kbn/data-plugin/public';
import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
+import type { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
import { DataViewSpec } from '@kbn/data-views-plugin/common';
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common';
import { VIEW_MODE } from './constants';
@@ -70,6 +71,11 @@ export interface DiscoverAppLocatorParams extends SerializableRecord {
*/
columns?: string[];
+ /**
+ * Data Grid related state
+ */
+ grid?: DiscoverGridSettings;
+
/**
* Used interval of the histogram
*/
@@ -139,6 +145,7 @@ export class DiscoverAppLocatorDefinition implements LocatorDefinition Get links -> Snapshot
const params: DiscoverAppLocatorParams = {
- ...otherState,
+ ...appState,
...(savedSearch.id ? { savedSearchId: savedSearch.id } : {}),
...(dataView?.isPersisted()
? { dataViewId: dataView?.id }
diff --git a/src/plugins/discover/public/application/main/services/discover_app_state_container.ts b/src/plugins/discover/public/application/main/services/discover_app_state_container.ts
index facf8e26fb851..e1614bf796391 100644
--- a/src/plugins/discover/public/application/main/services/discover_app_state_container.ts
+++ b/src/plugins/discover/public/application/main/services/discover_app_state_container.ts
@@ -24,7 +24,7 @@ import { SavedSearch, VIEW_MODE } from '@kbn/saved-search-plugin/public';
import { IKbnUrlStateStorage, ISyncStateRef, syncState } from '@kbn/kibana-utils-plugin/public';
import { isEqual } from 'lodash';
import { connectToQueryState, syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public';
-import type { UnifiedDataTableSettings } from '@kbn/unified-data-table';
+import type { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
import type { DiscoverServices } from '../../../build_services';
import { addLog } from '../../../utils/add_log';
import { cleanupUrlState } from '../utils/cleanup_url_state';
@@ -94,7 +94,7 @@ export interface DiscoverAppState {
/**
* Data Grid related state
*/
- grid?: UnifiedDataTableSettings;
+ grid?: DiscoverGridSettings;
/**
* Hide chart
*/
diff --git a/src/plugins/discover/public/application/main/services/discover_state.ts b/src/plugins/discover/public/application/main/services/discover_state.ts
index 1dc58643ebdc0..8994afb8a5f96 100644
--- a/src/plugins/discover/public/application/main/services/discover_state.ts
+++ b/src/plugins/discover/public/application/main/services/discover_state.ts
@@ -570,6 +570,7 @@ function createUrlGeneratorState({
: data.query.timefilter.timefilter.getTime(),
searchSessionId: shouldRestoreSearchSession ? data.search.session.getSessionId() : undefined,
columns: appState.columns,
+ grid: appState.grid,
sort: appState.sort,
savedQuery: appState.savedQuery,
interval: appState.interval,
diff --git a/src/plugins/saved_search/common/types.ts b/src/plugins/saved_search/common/types.ts
index c47548aebd8d4..acb98d26a0d14 100644
--- a/src/plugins/saved_search/common/types.ts
+++ b/src/plugins/saved_search/common/types.ts
@@ -9,13 +9,14 @@
import type { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common';
import type { SavedObjectReference } from '@kbn/core-saved-objects-server';
import type { SavedObjectsResolveResponse } from '@kbn/core/server';
+import type { SerializableRecord } from '@kbn/utility-types';
import { VIEW_MODE } from '.';
-export interface DiscoverGridSettings {
+export interface DiscoverGridSettings extends SerializableRecord {
columns?: Record;
}
-export interface DiscoverGridSettingsColumn {
+export interface DiscoverGridSettingsColumn extends SerializableRecord {
width?: number;
}
@@ -25,9 +26,7 @@ export interface SavedSearchAttributes {
sort: Array<[string, string]>;
columns: string[];
description: string;
- grid: {
- columns?: Record;
- };
+ grid: DiscoverGridSettings;
hideChart: boolean;
isTextBasedQuery: boolean;
usesAdHocDataView?: boolean;
@@ -59,9 +58,7 @@ export interface SavedSearch {
columns?: string[];
description?: string;
tags?: string[] | undefined;
- grid?: {
- columns?: Record;
- };
+ grid?: DiscoverGridSettings;
hideChart?: boolean;
viewMode?: VIEW_MODE;
hideAggregatedPreview?: boolean;
diff --git a/src/plugins/saved_search/tsconfig.json b/src/plugins/saved_search/tsconfig.json
index 7ed2cb4e82119..b1aa1679469ee 100644
--- a/src/plugins/saved_search/tsconfig.json
+++ b/src/plugins/saved_search/tsconfig.json
@@ -31,6 +31,7 @@
"@kbn/discover-utils",
"@kbn/logging",
"@kbn/core-plugins-server",
+ "@kbn/utility-types",
],
"exclude": [
"target/**/*",
From 99763dc61647c817384019f6603de7ad258eea01 Mon Sep 17 00:00:00 2001
From: Drew Tate
Date: Tue, 19 Dec 2023 08:32:31 -0700
Subject: [PATCH 07/95] [Lens] Fix context formula functions (#172710)
## Summary
Fix https://github.com/elastic/kibana/issues/170762
https://github.com/elastic/kibana/assets/315764/f5b50ffa-4a03-45ee-bc7a-2f2aca7fa3bd
### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../kbn-es-query/src/expressions/types.ts | 1 +
packages/kbn-optimizer/limits.yml | 2 +-
.../__snapshots__/kibana.test.ts.snap | 1 +
.../common/search/expressions/kibana.test.ts | 1 +
.../data/common/search/expressions/kibana.ts | 1 +
.../expression_functions/specs/index.ts | 1 +
.../expression_functions/specs/math_column.ts | 6 +-
.../common/expression_functions/types.ts | 2 +
.../formula_context/context_fns.test.ts | 91 ++++++++++++++++
.../formula_context/context_fns.ts | 97 +++++++++++++++++
.../expressions/formula_context/index.ts | 8 ++
.../plugins/lens/common/expressions/index.ts | 1 +
.../formula/context_variables.test.ts | 101 ------------------
.../definitions/formula/context_variables.tsx | 77 ++++++-------
.../config_panel/config_panel.test.tsx | 1 +
.../workspace_panel/workspace_panel.tsx | 17 +--
.../lens/public/embeddable/embeddable.tsx | 1 +
x-pack/plugins/lens/public/expressions.ts | 8 ++
.../lens/public/state_management/selectors.ts | 3 +
.../lens/server/expressions/expressions.ts | 6 ++
.../translations/translations/fr-FR.json | 3 -
.../translations/translations/ja-JP.json | 3 -
.../translations/translations/zh-CN.json | 3 -
23 files changed, 264 insertions(+), 171 deletions(-)
create mode 100644 x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts
create mode 100644 x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts
create mode 100644 x-pack/plugins/lens/common/expressions/formula_context/index.ts
diff --git a/packages/kbn-es-query/src/expressions/types.ts b/packages/kbn-es-query/src/expressions/types.ts
index 42dc021c9b752..ed367adc7973a 100644
--- a/packages/kbn-es-query/src/expressions/types.ts
+++ b/packages/kbn-es-query/src/expressions/types.ts
@@ -9,6 +9,7 @@
import { Filter, Query, TimeRange } from '../filters';
export interface ExecutionContextSearch {
+ now?: number;
filters?: Filter[];
query?: Query | Query[];
timeRange?: TimeRange;
diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index 1e4c82b5226df..d38e1399ed3aa 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -86,7 +86,7 @@ pageLoadAssetSize:
kibanaUsageCollection: 16463
kibanaUtils: 79713
kubernetesSecurity: 77234
- lens: 39000
+ lens: 41000
licenseManagement: 41817
licensing: 29004
links: 44490
diff --git a/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap b/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap
index 2400f7a1f67d6..7bcf782fbbbc2 100644
--- a/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap
+++ b/src/plugins/data/common/search/expressions/__snapshots__/kibana.test.ts.snap
@@ -14,6 +14,7 @@ Object {
},
},
],
+ "now": 0,
"query": Array [
Object {
"language": "lucene",
diff --git a/src/plugins/data/common/search/expressions/kibana.test.ts b/src/plugins/data/common/search/expressions/kibana.test.ts
index c82bc0293cefe..4992a345bd0d2 100644
--- a/src/plugins/data/common/search/expressions/kibana.test.ts
+++ b/src/plugins/data/common/search/expressions/kibana.test.ts
@@ -20,6 +20,7 @@ describe('interpreter/functions#kibana', () => {
beforeEach(() => {
input = { timeRange: { from: '0', to: '1' } };
search = {
+ now: 0,
type: 'kibana_context',
query: { language: 'lucene', query: 'geo.src:US' },
filters: [
diff --git a/src/plugins/data/common/search/expressions/kibana.ts b/src/plugins/data/common/search/expressions/kibana.ts
index 83d2cdc1c64b9..ad8405a51418c 100644
--- a/src/plugins/data/common/search/expressions/kibana.ts
+++ b/src/plugins/data/common/search/expressions/kibana.ts
@@ -41,6 +41,7 @@ export const kibana: ExpressionFunctionKibana = {
// TODO: But it shouldn't be need.
...input,
type: 'kibana_context',
+ now: getSearchContext().now ?? Date.now(),
query: [...toArray(getSearchContext().query), ...toArray((input || {}).query)],
filters: [...(getSearchContext().filters || []), ...((input || {}).filters || [])],
timeRange: getSearchContext().timeRange || (input ? input.timeRange : undefined),
diff --git a/src/plugins/expressions/common/expression_functions/specs/index.ts b/src/plugins/expressions/common/expression_functions/specs/index.ts
index 0e473e4a79e5a..37af3ede5ebe0 100644
--- a/src/plugins/expressions/common/expression_functions/specs/index.ts
+++ b/src/plugins/expressions/common/expression_functions/specs/index.ts
@@ -17,6 +17,7 @@ export * from './overall_metric';
export * from './derivative';
export * from './moving_average';
export * from './ui_setting';
+export * from './math_column';
export type { MapColumnArguments } from './map_column';
export { mapColumn } from './map_column';
export type { MathArguments, MathInput } from './math';
diff --git a/src/plugins/expressions/common/expression_functions/specs/math_column.ts b/src/plugins/expressions/common/expression_functions/specs/math_column.ts
index e056bc6b876e1..6b75af7de4ca9 100644
--- a/src/plugins/expressions/common/expression_functions/specs/math_column.ts
+++ b/src/plugins/expressions/common/expression_functions/specs/math_column.ts
@@ -18,12 +18,14 @@ export type MathColumnArguments = MathArguments & {
copyMetaFrom?: string | null;
};
-export const mathColumn: ExpressionFunctionDefinition<
+export type ExpressionFunctionMathColumn = ExpressionFunctionDefinition<
'mathColumn',
Datatable,
MathColumnArguments,
Promise
-> = {
+>;
+
+export const mathColumn: ExpressionFunctionMathColumn = {
name: 'mathColumn',
type: 'datatable',
inputTypes: ['datatable'],
diff --git a/src/plugins/expressions/common/expression_functions/types.ts b/src/plugins/expressions/common/expression_functions/types.ts
index 018ee9e9fac0c..c59169ccf04ab 100644
--- a/src/plugins/expressions/common/expression_functions/types.ts
+++ b/src/plugins/expressions/common/expression_functions/types.ts
@@ -20,6 +20,7 @@ import {
ExpressionFunctionDerivative,
ExpressionFunctionMovingAverage,
ExpressionFunctionOverallMetric,
+ ExpressionFunctionMathColumn,
} from './specs';
import { ExpressionAstFunction } from '../ast';
@@ -132,4 +133,5 @@ export interface ExpressionFunctionDefinitions {
overall_metric: ExpressionFunctionOverallMetric;
derivative: ExpressionFunctionDerivative;
moving_average: ExpressionFunctionMovingAverage;
+ math_column: ExpressionFunctionMathColumn;
}
diff --git a/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts
new file mode 100644
index 0000000000000..f064238992b07
--- /dev/null
+++ b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.test.ts
@@ -0,0 +1,91 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { ExecutionContext } from '@kbn/expressions-plugin/common';
+import { Adapters } from '@kbn/inspector-plugin/common';
+import { formulaIntervalFn, formulaNowFn, formulaTimeRangeFn } from './context_fns';
+
+describe('interval', () => {
+ it('should return 0 if no time range available', () => {
+ // (not sure if this case is actually possible)
+ const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, {
+ getSearchContext: () => ({
+ /* no time range */
+ }),
+ } as ExecutionContext);
+ expect(result).toEqual(0);
+ });
+
+ it('should return 0 if no targetBars is passed', () => {
+ const result = formulaIntervalFn.fn(
+ undefined,
+ {
+ /* no targetBars */
+ },
+ {
+ getSearchContext: () => ({
+ timeRange: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ }),
+ } as ExecutionContext
+ );
+ expect(result).toEqual(0);
+ });
+
+ it('should return a valid value > 0 if both timeRange and targetBars is passed', () => {
+ const result = formulaIntervalFn.fn(undefined, { targetBars: 100 }, {
+ getSearchContext: () => ({
+ timeRange: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ }),
+ } as ExecutionContext);
+ expect(result).toEqual(10000);
+ });
+});
+
+describe('time range', () => {
+ it('should return 0 if no time range is available', () => {
+ // (not sure if this case is actually possible)
+ const result = formulaTimeRangeFn.fn(undefined, {}, {
+ getSearchContext: () => ({
+ /* no time range */
+ }),
+ } as ExecutionContext);
+ expect(result).toEqual(0);
+ });
+
+ it('should return a valid value > 0 if time range is available', () => {
+ const result = formulaTimeRangeFn.fn(undefined, {}, {
+ getSearchContext: () => ({
+ timeRange: {
+ from: 'now-15m',
+ to: 'now',
+ },
+ now: 1000000, // important to provide this to make the result consistent
+ }),
+ } as ExecutionContext);
+
+ expect(result).toBe(900000);
+ });
+});
+
+describe('now', () => {
+ it('should return the now value when passed', () => {
+ const now = 123456789;
+ expect(
+ formulaNowFn.fn(undefined, {}, {
+ getSearchContext: () => ({
+ now,
+ }),
+ } as ExecutionContext)
+ ).toEqual(now);
+ });
+});
diff --git a/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts
new file mode 100644
index 0000000000000..2f77d1142f7d1
--- /dev/null
+++ b/x-pack/plugins/lens/common/expressions/formula_context/context_fns.ts
@@ -0,0 +1,97 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { getAbsoluteTimeRange, calcAutoIntervalNear } from '@kbn/data-plugin/common';
+import type { TimeRange } from '@kbn/es-query';
+import type { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common';
+import moment from 'moment';
+import { i18n } from '@kbn/i18n';
+
+export type ExpressionFunctionFormulaTimeRange = ExpressionFunctionDefinition<
+ 'formula_time_range',
+ undefined,
+ object,
+ number
+>;
+
+const getTimeRangeAsNumber = (timeRange: TimeRange | undefined, now: number | undefined) => {
+ if (!timeRange) return 0;
+ const absoluteTimeRange = getAbsoluteTimeRange(
+ timeRange,
+ now != null ? { forceNow: new Date(now) } : {}
+ );
+ return timeRange ? moment(absoluteTimeRange.to).diff(moment(absoluteTimeRange.from)) : 0;
+};
+
+export const formulaTimeRangeFn: ExpressionFunctionFormulaTimeRange = {
+ name: 'formula_time_range',
+
+ help: i18n.translate('xpack.lens.formula.timeRange.help', {
+ defaultMessage: 'The specified time range, in milliseconds (ms).',
+ }),
+
+ args: {},
+
+ fn(_input, _args, { getSearchContext }) {
+ const { timeRange, now } = getSearchContext();
+ return getTimeRangeAsNumber(timeRange, now);
+ },
+};
+
+export type ExpressionFunctionFormulaInterval = ExpressionFunctionDefinition<
+ 'formula_interval',
+ undefined,
+ {
+ targetBars?: number;
+ },
+ number
+>;
+
+export const formulaIntervalFn: ExpressionFunctionFormulaInterval = {
+ name: 'formula_interval',
+
+ help: i18n.translate('xpack.lens.formula.interval.help', {
+ defaultMessage: 'The specified minimum interval for the date histogram, in milliseconds (ms).',
+ }),
+
+ args: {
+ targetBars: {
+ types: ['number'],
+ help: i18n.translate('xpack.lens.formula.interval.targetBars.help', {
+ defaultMessage: 'The target number of bars for the date histogram.',
+ }),
+ },
+ },
+
+ fn(_input, args, { getSearchContext }) {
+ const { timeRange, now } = getSearchContext();
+ return timeRange && args.targetBars
+ ? calcAutoIntervalNear(args.targetBars, getTimeRangeAsNumber(timeRange, now)).asMilliseconds()
+ : 0;
+ },
+};
+
+export type ExpressionFunctionFormulaNow = ExpressionFunctionDefinition<
+ 'formula_now',
+ undefined,
+ object,
+ number
+>;
+
+export const formulaNowFn: ExpressionFunctionFormulaNow = {
+ name: 'formula_now',
+
+ help: i18n.translate('xpack.lens.formula.now.help', {
+ defaultMessage: 'The current now moment used in Kibana expressed in milliseconds (ms).',
+ }),
+
+ args: {},
+
+ fn(_input, _args, { getSearchContext }) {
+ return getSearchContext().now ?? Date.now();
+ },
+};
diff --git a/x-pack/plugins/lens/common/expressions/formula_context/index.ts b/x-pack/plugins/lens/common/expressions/formula_context/index.ts
new file mode 100644
index 0000000000000..da8931779cfbe
--- /dev/null
+++ b/x-pack/plugins/lens/common/expressions/formula_context/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 * from './context_fns';
diff --git a/x-pack/plugins/lens/common/expressions/index.ts b/x-pack/plugins/lens/common/expressions/index.ts
index ccb6343334d62..c3ccaddac9fd3 100644
--- a/x-pack/plugins/lens/common/expressions/index.ts
+++ b/x-pack/plugins/lens/common/expressions/index.ts
@@ -11,3 +11,4 @@ export * from './format_column';
export * from './map_to_columns';
export * from './time_scale';
export * from './datatable';
+export * from './formula_context';
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts
index 407f458a11e3e..db38e18d3bd19 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.test.ts
@@ -34,20 +34,6 @@ function createLayer(
};
}
-function createExpression(type: 'interval' | 'now' | 'time_range', value: number) {
- return [
- {
- type: 'function',
- function: 'mathColumn',
- arguments: {
- id: ['col1'],
- name: [`Constant: ${type}`],
- expression: [String(value)],
- },
- },
- ];
-}
-
describe('context variables', () => {
describe('interval', () => {
describe('getErrorMessages', () => {
@@ -124,53 +110,6 @@ describe('context variables', () => {
).toBeUndefined();
});
});
- describe('toExpression', () => {
- it('should return 0 if no dateRange is passed', () => {
- expect(
- intervalOperation.toExpression(
- createLayer('interval'),
- 'col1',
- createMockedIndexPattern(),
- { now: new Date(), targetBars: 100 }
- )
- ).toEqual(expect.arrayContaining(createExpression('interval', 0)));
- });
-
- it('should return 0 if no targetBars is passed', () => {
- expect(
- intervalOperation.toExpression(
- createLayer('interval'),
- 'col1',
- createMockedIndexPattern(),
- {
- dateRange: {
- fromDate: new Date(2022, 0, 1).toISOString(),
- toDate: new Date(2023, 0, 1).toISOString(),
- },
- now: new Date(),
- }
- )
- ).toEqual(expect.arrayContaining(createExpression('interval', 0)));
- });
-
- it('should return a valid value > 0 if both dateRange and targetBars is passed', () => {
- expect(
- intervalOperation.toExpression(
- createLayer('interval'),
- 'col1',
- createMockedIndexPattern(),
- {
- dateRange: {
- fromDate: new Date(2022, 0, 1).toISOString(),
- toDate: new Date(2023, 0, 1).toISOString(),
- },
- now: new Date(),
- targetBars: 100,
- }
- )
- ).toEqual(expect.arrayContaining(createExpression('interval', 86400000)));
- });
- });
});
describe('time_range', () => {
describe('getErrorMessages', () => {
@@ -202,35 +141,6 @@ describe('context variables', () => {
).toEqual(expect.arrayContaining(['The current time range interval is not available']));
});
});
-
- describe('toExpression', () => {
- it('should return 0 if no dateRange is passed', () => {
- expect(
- timeRangeOperation.toExpression(
- createLayer('time_range'),
- 'col1',
- createMockedIndexPattern(),
- { now: new Date(), targetBars: 100 }
- )
- ).toEqual(expect.arrayContaining(createExpression('time_range', 0)));
- });
-
- it('should return a valid value > 0 if dateRange is passed', () => {
- expect(
- timeRangeOperation.toExpression(
- createLayer('time_range'),
- 'col1',
- createMockedIndexPattern(),
- {
- dateRange: {
- fromDate: new Date(2022, 0, 1).toISOString(),
- toDate: new Date(2023, 0, 1).toISOString(),
- },
- }
- )
- ).toEqual(expect.arrayContaining(createExpression('time_range', 31536000000)));
- });
- });
});
describe('now', () => {
describe('getErrorMessages', () => {
@@ -240,16 +150,5 @@ describe('context variables', () => {
).toBeUndefined();
});
});
-
- describe('toExpression', () => {
- it('should return the now value when passed', () => {
- const now = new Date();
- expect(
- nowOperation.toExpression(createLayer('now'), 'col1', createMockedIndexPattern(), {
- now,
- })
- ).toEqual(expect.arrayContaining(createExpression('now', +now)));
- });
- });
});
});
diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx
index 4b7b5b94b493b..f5f28d94ad228 100644
--- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx
+++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/context_variables.tsx
@@ -6,9 +6,18 @@
*/
import { i18n } from '@kbn/i18n';
-import moment from 'moment';
-import { calcAutoIntervalNear, UI_SETTINGS } from '@kbn/data-plugin/common';
+import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { partition } from 'lodash';
+import {
+ buildExpressionFunction,
+ buildExpression,
+ ExpressionFunctionDefinitions,
+} from '@kbn/expressions-plugin/common';
+import {
+ ExpressionFunctionFormulaInterval,
+ ExpressionFunctionFormulaNow,
+ ExpressionFunctionFormulaTimeRange,
+} from '../../../../../../common/expressions/formula_context/context_fns';
import type {
DateHistogramIndexPatternColumn,
FormBasedLayer,
@@ -58,13 +67,9 @@ export interface TimeRangeIndexPatternColumn extends ReferenceBasedIndexPatternC
operationType: 'time_range';
}
-function getTimeRangeFromContext({ dateRange }: ContextValues) {
- return dateRange ? moment(dateRange.toDate).diff(moment(dateRange.fromDate)) : 0;
-}
-
function getTimeRangeErrorMessages(
- layer: FormBasedLayer,
- columnId: string,
+ _layer: FormBasedLayer,
+ _columnId: string,
indexPattern: IndexPattern,
dateRange?: DateRange | undefined
) {
@@ -89,12 +94,11 @@ function getTimeRangeErrorMessages(
export const timeRangeOperation = createContextValueBasedOperation({
type: 'time_range',
label: 'Time range',
- description: i18n.translate('xpack.lens.indexPattern.timeRange.documentation.markdown', {
- defaultMessage: `
-The specified time range, in milliseconds (ms).
- `,
+ description: i18n.translate('xpack.lens.formula.timeRange.help', {
+ defaultMessage: 'The specified time range, in milliseconds (ms).',
}),
- getContextValue: getTimeRangeFromContext,
+ getExpressionFunction: (_context: ContextValues) =>
+ buildExpressionFunction('formula_time_range', {}),
getErrorMessage: getTimeRangeErrorMessages,
});
@@ -102,9 +106,6 @@ export interface NowIndexPatternColumn extends ReferenceBasedIndexPatternColumn
operationType: 'now';
}
-function getNowFromContext({ now }: ContextValues) {
- return now == null ? Date.now() : +now;
-}
function getNowErrorMessage() {
return undefined;
}
@@ -112,12 +113,11 @@ function getNowErrorMessage() {
export const nowOperation = createContextValueBasedOperation({
type: 'now',
label: 'Current now',
- description: i18n.translate('xpack.lens.indexPattern.now.documentation.markdown', {
- defaultMessage: `
- The current now moment used in Kibana expressed in milliseconds (ms).
- `,
+ description: i18n.translate('xpack.lens.formula.now.help', {
+ defaultMessage: 'The current now moment used in Kibana expressed in milliseconds (ms).',
}),
- getContextValue: getNowFromContext,
+ getExpressionFunction: (_context: ContextValues) =>
+ buildExpressionFunction('formula_now', {}),
getErrorMessage: getNowErrorMessage,
});
@@ -125,12 +125,6 @@ export interface IntervalIndexPatternColumn extends ReferenceBasedIndexPatternCo
operationType: 'interval';
}
-function getIntervalFromContext(context: ContextValues) {
- return context.dateRange && context.targetBars
- ? calcAutoIntervalNear(context.targetBars, getTimeRangeFromContext(context)).asMilliseconds()
- : 0;
-}
-
function getIntervalErrorMessages(
layer: FormBasedLayer,
columnId: string,
@@ -174,12 +168,13 @@ function getIntervalErrorMessages(
export const intervalOperation = createContextValueBasedOperation({
type: 'interval',
label: 'Date histogram interval',
- description: i18n.translate('xpack.lens.indexPattern.interval.documentation.markdown', {
- defaultMessage: `
-The specified minimum interval for the date histogram, in milliseconds (ms).
- `,
+ description: i18n.translate('xpack.lens.formula.interval.help', {
+ defaultMessage: 'The specified minimum interval for the date histogram, in milliseconds (ms).',
}),
- getContextValue: getIntervalFromContext,
+ getExpressionFunction: ({ targetBars }: ContextValues) =>
+ buildExpressionFunction('formula_interval', {
+ targetBars,
+ }),
getErrorMessage: getIntervalErrorMessages,
});
@@ -191,14 +186,14 @@ export type ConstantsIndexPatternColumn =
function createContextValueBasedOperation({
label,
type,
- getContextValue,
+ getExpressionFunction,
getErrorMessage,
description,
}: {
label: string;
type: ColumnType['operationType'];
description: string;
- getContextValue: (context: ContextValues) => number;
+ getExpressionFunction: (context: ContextValues) => ReturnType;
getErrorMessage: OperationDefinition['getErrorMessage'];
}): OperationDefinition {
return {
@@ -233,15 +228,11 @@ function createContextValueBasedOperation {
const column = layer.columns[columnId] as ColumnType;
return [
- {
- type: 'function',
- function: 'mathColumn',
- arguments: {
- id: [columnId],
- name: [column.label],
- expression: [String(getContextValue(context))],
- },
- },
+ buildExpressionFunction('mathColumn', {
+ id: columnId,
+ name: column.label,
+ expression: buildExpression([getExpressionFunction(context)]),
+ }).toAst(),
];
},
createCopy(layers, source, target) {
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
index b0729cb489ba7..04d69c1afc571 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/config_panel.test.tsx
@@ -484,6 +484,7 @@ describe('ConfigPanel', () => {
},
dateRange: expect.anything(),
filters: [],
+ now: expect.anything(),
query: undefined,
},
groupId: 'a',
diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx
index 73a4ef853390d..bc3b71c08487a 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx
@@ -24,7 +24,6 @@ import {
} from '@elastic/eui';
import type { CoreStart } from '@kbn/core/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
-import type { ExecutionContextSearch } from '@kbn/es-query';
import type {
ExpressionRendererEvent,
ExpressionRenderError,
@@ -66,7 +65,6 @@ import {
editVisualizationAction,
setSaveable,
useLensSelector,
- selectExecutionContext,
selectIsFullscreenDatasource,
selectVisualization,
selectDatasourceStates,
@@ -80,6 +78,7 @@ import {
VisualizationState,
DatasourceStates,
DataViewsState,
+ selectExecutionContextSearch,
} from '../../../state_management';
import type { LensInspector } from '../../../lens_inspector_service';
import { inferTimeField, DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS } from '../../../utils';
@@ -712,7 +711,7 @@ export const VisualizationWrapper = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- const context = useLensSelector(selectExecutionContext);
+ const searchContext = useLensSelector(selectExecutionContextSearch);
// Used for reporting
const { isRenderComplete, hasDynamicError, setIsRenderComplete, setDynamicError, nodeRef } =
useReportingState(errors);
@@ -722,18 +721,6 @@ export const VisualizationWrapper = ({
onRender$();
}, [setIsRenderComplete, onRender$]);
- const searchContext: ExecutionContextSearch = useMemo(
- () => ({
- query: context.query,
- timeRange: {
- from: context.dateRange.fromDate,
- to: context.dateRange.toDate,
- },
- filters: context.filters,
- disableWarningToasts: true,
- }),
- [context]
- );
const searchSessionId = useLensSelector(selectSearchSessionId);
if (errors.length) {
diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx
index 9851a10c8641c..e5d34db62ba75 100644
--- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx
+++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx
@@ -1253,6 +1253,7 @@ export class Embeddable
const input = this.getInput();
const context: ExecutionContextSearch = {
+ now: this.deps.data.nowProvider.get().getTime(),
timeRange:
input.timeslice !== undefined
? {
diff --git a/x-pack/plugins/lens/public/expressions.ts b/x-pack/plugins/lens/public/expressions.ts
index ef12b43bec71d..32856175db1b0 100644
--- a/x-pack/plugins/lens/public/expressions.ts
+++ b/x-pack/plugins/lens/public/expressions.ts
@@ -14,6 +14,11 @@ import { formatColumn } from '../common/expressions/format_column';
import { counterRate } from '../common/expressions/counter_rate';
import { getTimeScale } from '../common/expressions/time_scale/time_scale';
import { collapse } from '../common/expressions/collapse';
+import {
+ formulaIntervalFn,
+ formulaNowFn,
+ formulaTimeRangeFn,
+} from '../common/expressions/formula_context';
type TimeScaleArguments = Parameters;
@@ -25,6 +30,9 @@ export const setupExpressions = (
getForceNow: TimeScaleArguments[2]
) => {
[
+ formulaTimeRangeFn,
+ formulaNowFn,
+ formulaIntervalFn,
collapse,
counterRate,
formatColumn,
diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts
index 7572c31287297..44121c4d064c7 100644
--- a/x-pack/plugins/lens/public/state_management/selectors.ts
+++ b/x-pack/plugins/lens/public/state_management/selectors.ts
@@ -46,9 +46,11 @@ export const selectTriggerApplyChanges = (state: LensState) => {
return shouldApply;
};
+// TODO - is there any point to keeping this around since we have selectExecutionSearchContext?
export const selectExecutionContext = createSelector(
[selectQuery, selectFilters, selectResolvedDateRange],
(query, filters, dateRange) => ({
+ now: Date.now(),
dateRange,
query,
filters,
@@ -56,6 +58,7 @@ export const selectExecutionContext = createSelector(
);
export const selectExecutionContextSearch = createSelector(selectExecutionContext, (res) => ({
+ now: res.now,
query: res.query,
timeRange: {
from: res.dateRange.fromDate,
diff --git a/x-pack/plugins/lens/server/expressions/expressions.ts b/x-pack/plugins/lens/server/expressions/expressions.ts
index 1e80fc5bb49a3..b5e8fc2851608 100644
--- a/x-pack/plugins/lens/server/expressions/expressions.ts
+++ b/x-pack/plugins/lens/server/expressions/expressions.ts
@@ -13,6 +13,9 @@ import {
mapToColumns,
getTimeScale,
getDatatable,
+ formulaIntervalFn,
+ formulaNowFn,
+ formulaTimeRangeFn,
} from '../../common/expressions';
import { getDatatableUtilitiesFactory, getFormatFactory, getTimeZoneFactory } from './utils';
@@ -23,6 +26,9 @@ export const setupExpressions = (
expressions: ExpressionsServerSetup
) => {
[
+ formulaNowFn,
+ formulaIntervalFn,
+ formulaTimeRangeFn,
counterRate,
formatColumn,
mapToColumns,
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index b6816376aa061..6acdf51501610 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -21980,11 +21980,9 @@
"xpack.lens.indexPattern.counterRate.documentation.markdown": "\nCalcule le taux d'un compteur toujours croissant. Cette fonction renvoie uniquement des résultats utiles inhérents aux champs d'indicateurs de compteur qui contiennent une mesure quelconque à croissance régulière.\nSi la valeur diminue, elle est interprétée comme une mesure de réinitialisation de compteur. Pour obtenir des résultats plus précis, \"counter_rate\" doit être calculé d’après la valeur \"max\" du champ.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\nIl utilise l'intervalle en cours utilisé dans la formule.\n\nExemple : visualiser le taux d'octets reçus au fil du temps par un serveur Memcached :\n`counter_rate(max(memcached.stats.read.bytes))`\n ",
"xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\nCalcule la somme cumulée d'un indicateur au fil du temps, en ajoutant toutes les valeurs précédentes d'une série à chaque valeur. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser les octets reçus cumulés au fil du temps :\n`cumulative_sum(sum(bytes))`\n ",
"xpack.lens.indexPattern.differences.documentation.markdown": "\nCalcule la différence par rapport à la dernière valeur d'un indicateur au fil du temps. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLes données doivent être séquentielles pour les différences. Si vos données sont vides lorsque vous utilisez des différences, essayez d'augmenter l'intervalle de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser la modification des octets reçus au fil du temps :\n`differences(sum(bytes))`\n ",
- "xpack.lens.indexPattern.interval.documentation.markdown": "\nL’intervalle minimum spécifié pour l’histogramme de date, en millisecondes (ms).\n ",
"xpack.lens.indexPattern.lastValue.documentation.markdown": "\nRenvoie la valeur d'un champ du dernier document, triée par le champ d'heure par défaut de la vue de données.\n\nCette fonction permet de récupérer le dernier état d'une entité.\n\nExemple : obtenir le statut actuel du serveur A :\n`last_value(server.status, kql='server.name=\"A\"')`\n ",
"xpack.lens.indexPattern.metric.documentation.markdown": "\nRenvoie l'indicateur {metric} d'un champ. Cette fonction fonctionne uniquement pour les champs numériques.\n\nExemple : obtenir l'indicateur {metric} d'un prix :\n\"{metric}(price)\"\n\nExemple : obtenir l'indicateur {metric} d'un prix pour des commandes du Royaume-Uni :\n\"{metric}(price, kql='location:UK')\"\n ",
"xpack.lens.indexPattern.movingAverage.documentation.markdown": "\nCalcule la moyenne mobile d'un indicateur au fil du temps, en prenant la moyenne des n dernières valeurs pour calculer la valeur actuelle. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLa valeur de fenêtre par défaut est {defaultValue}.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nPrend un paramètre nommé \"window\" qui spécifie le nombre de dernières valeurs à inclure dans le calcul de la moyenne de la valeur actuelle.\n\nExemple : lisser une ligne de mesures :\n`moving_average(sum(bytes), window=5)`\n ",
- "xpack.lens.indexPattern.now.documentation.markdown": "\n La durée actuelle passée dans Kibana exprimée en millisecondes (ms).\n ",
"xpack.lens.indexPattern.overall_average.documentation.markdown": "\nCalcule la moyenne d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_average\" calcule la moyenne pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : écart par rapport à la moyenne :\n\"sum(bytes) - overall_average(sum(bytes))\"\n ",
"xpack.lens.indexPattern.overall_max.documentation.markdown": "\nCalcule la valeur maximale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_max\" calcule la valeur maximale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : pourcentage de plage\n\"(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))\"\n ",
"xpack.lens.indexPattern.overall_min.documentation.markdown": "\nCalcule la valeur minimale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, \"overall_min\" calcule la valeur minimale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : pourcentage de plage\n\"(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))\"\n ",
@@ -21993,7 +21991,6 @@
"xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\nRetourne le pourcentage de valeurs qui sont en dessous d'une certaine valeur. Par exemple, si une valeur est supérieure à 95 % des valeurs observées, elle est placée au 95e rang centile.\n\nExemple : Obtenir le pourcentage de valeurs qui sont en dessous de 100 :\n\"percentile_rank(bytes, value=100)\"\n ",
"xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\nRetourne la taille de la variation ou de la dispersion du champ. Cette fonction ne s’applique qu’aux champs numériques.\n\n#### Exemples\n\nPour obtenir l'écart type d'un prix, utilisez standard_deviation(price).\n\nPour obtenir la variance du prix des commandes passées au Royaume-Uni, utilisez `square(standard_deviation(price, kql='location:UK'))`.\n ",
"xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\nCette fonction avancée est utile pour normaliser les comptes et les sommes sur un intervalle de temps spécifique. Elle permet l'intégration avec les indicateurs qui sont stockés déjà normalisés sur un intervalle de temps spécifique.\n\nVous pouvez faire appel à cette fonction uniquement si une fonction d'histogramme des dates est utilisée dans le graphique actuel.\n\nExemple : Un rapport comparant un indicateur déjà normalisé à un autre indicateur devant être normalisé.\n\"normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)\"\n ",
- "xpack.lens.indexPattern.timeRange.documentation.markdown": "\nL'intervalle de temps spécifié, en millisecondes (ms).\n ",
"xpack.lens.AggBasedLabel": "visualisation basée sur l'agrégation",
"xpack.lens.app.addToLibrary": "Enregistrer dans la bibliothèque",
"xpack.lens.app.cancel": "Annuler",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 9ae21a4439e8a..0ed5b8922a49f 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -21995,11 +21995,9 @@
"xpack.lens.indexPattern.counterRate.documentation.markdown": "\n増加し続けるカウンターのレートを計算します。この関数は、経時的に単調に増加する種類の測定を含むカウンターメトリックフィールドでのみ結果を生成します。\n値が小さくなる場合は、カウンターリセットであると解釈されます。最も正確な結果を得るには、フィールドの「max`」で「counter_rate」を計算してください。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n式で使用されるときには、現在の間隔を使用します。\n\n例:Memcachedサーバーで経時的に受信されたバイトの比率を可視化します。\n`counter_rate(max(memcached.stats.read.bytes))`\n ",
"xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\n経時的なメトリックの累計値を計算し、系列のすべての前の値を各値に追加します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n例:経時的に累積された受信バイト数を可視化します。\n`cumulative_sum(sum(bytes))`\n ",
"xpack.lens.indexPattern.differences.documentation.markdown": "\n経時的にメトリックの最後の値に対する差異を計算します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\n差異ではデータが連続する必要があります。差異を使用するときにデータが空の場合は、データヒストグラム間隔を大きくしてみてください。\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n例:経時的に受信したバイト数の変化を可視化します。\n`differences(sum(bytes))`\n ",
- "xpack.lens.indexPattern.interval.documentation.markdown": "\nミリ秒(ms)で指定した、日付ヒストグラムの最小間隔。\n ",
"xpack.lens.indexPattern.lastValue.documentation.markdown": "\n最後のドキュメントからフィールドの値を返し、データビューのデフォルト時刻フィールドで並べ替えます。\n\nこの関数はエンティティの最新の状態を取得する際に役立ちます。\n\n例:サーバーAの現在のステータスを取得:\n`last_value(server.status, kql='server.name=\"A\"')`\n ",
"xpack.lens.indexPattern.metric.documentation.markdown": "\nフィールドの{metric}を返します。この関数は数値フィールドでのみ動作します。\n\n例:価格の{metric}を取得:\n`{metric}(price)`\n\n例:英国からの注文の価格の{metric}を取得:\n`{metric}(price, kql='location:UK')`\n ",
"xpack.lens.indexPattern.movingAverage.documentation.markdown": "\n経時的なメトリックの移動平均を計算します。最後のn番目の値を平均化し、現在の値を計算します。この関数を使用するには、日付ヒストグラムディメンションも構成する必要があります。\nデフォルトウィンドウ値は{defaultValue}です\n\nこの計算はフィルターで定義された別の系列または上位値のディメンションに対して個別に実行されます。\n\n指名パラメーター「window」を取ります。これは現在値の平均計算に含める最後の値の数を指定します。\n\n例:測定の線を平滑化:\n`moving_average(sum(bytes), window=5)`\n ",
- "xpack.lens.indexPattern.now.documentation.markdown": "\n ミリ秒(ms)で表された、Kibanaで使用される現在の日時。\n ",
"xpack.lens.indexPattern.overall_average.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの平均を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_average」はすべてのディメンションで平均値を計算します。\n\n例:平均からの収束:\n`sum(bytes) - overall_average(sum(bytes))`\n ",
"xpack.lens.indexPattern.overall_max.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの最大値を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_max」はすべてのディメンションで最大値を計算します。\n\n例:範囲の割合\n`(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ",
"xpack.lens.indexPattern.overall_min.documentation.markdown": "\n現在のグラフの系列のすべてのデータポイントのメトリックの最小値を計算します。系列は日付ヒストグラムまたは間隔関数を使用してディメンションによって定義されます。\n上位の値やフィルターなどのデータを分解する他のディメンションは別の系列として処理されます。\n\n日付ヒストグラムまたは間隔関数が現在のグラフで使用されている場合、使用されている関数に関係なく、「overall_min」はすべてのディメンションで最小値を計算します。\n\n例:範囲の割合\n`(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ",
@@ -22008,7 +22006,6 @@
"xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\n特定の値未満の値の割合が返されます。たとえば、値が観察された値の95%以上の場合、95パーセンタイルランクであるとされます。\n\n例:100未満の値のパーセンタイルを取得します。\n`percentile_rank(bytes, value=100)`\n ",
"xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\nフィールドの分散または散布度が返されます。この関数は数値フィールドでのみ動作します。\n\n#### 例\n\n価格の標準偏差を取得するには、standard_deviation(price)を使用します。\n\n英国からの注文書の価格の分散を取得するには、square(standard_deviation(price, kql='location:UK'))を使用します。\n ",
"xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\nこの高度な機能は、特定の期間に対してカウントと合計を正規化する際に役立ちます。すでに特定の期間に対して正規化され、保存されたメトリックとの統合が可能です。\n\nこの機能は、現在のグラフで日付ヒストグラム関数が使用されている場合にのみ使用できます。\n\n例:すでに正規化されているメトリックを、正規化が必要な別のメトリックと比較した比率。\n`normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`\n ",
- "xpack.lens.indexPattern.timeRange.documentation.markdown": "\nミリ秒(ms)で指定された時間範囲。\n ",
"xpack.lens.AggBasedLabel": "集約に基づく可視化",
"xpack.lens.app.addToLibrary": "ライブラリに保存",
"xpack.lens.app.cancel": "キャンセル",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index fcfce0f121c37..2def05af32b75 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -21994,11 +21994,9 @@
"xpack.lens.indexPattern.counterRate.documentation.markdown": "\n计算不断增大的计数器的速率。此函数将仅基于计数器指标字段生成有帮助的结果,包括随着时间的推移度量某种单调递增。\n如果值确实变小,则其将此解析为计数器重置。要获取很精确的结果,应基于字段的 `max`计算 `counter_rate`。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n用于公式中时,其使用当前时间间隔。\n\n例如:可视化随着时间的推移 Memcached 服务器接收的字节速率:\n`counter_rate(max(memcached.stats.read.bytes))`\n ",
"xpack.lens.indexPattern.cumulativeSum.documentation.markdown": "\n计算随着时间的推移指标的累计和,即序列的所有以前值相加得出每个值。要使用此函数,您还需要配置 Date Histogram 维度。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n例如:可视化随着时间的推移累计接收的字节:\n`cumulative_sum(sum(bytes))`\n ",
"xpack.lens.indexPattern.differences.documentation.markdown": "\n计算随着时间的推移与指标最后一个值的差异。要使用此函数,您还需要配置 Date Histogram 维度。\n差异需要数据是顺序的。如果使用差异时数据为空,请尝试增加 Date Histogram 时间间隔。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n例如:可视化随着时间的推移接收的字节的变化:\n`differences(sum(bytes))`\n ",
- "xpack.lens.indexPattern.interval.documentation.markdown": "\nDate Histogram 的指定最小时间间隔,单位为毫秒 (ms)。\n ",
"xpack.lens.indexPattern.lastValue.documentation.markdown": "\n返回最后一个文档的字段值,按数据视图的默认时间字段排序。\n\n此函数用于检索实体的最新状态。\n\n例如:获取服务器 A 的当前状态:\n`last_value(server.status, kql='server.name=\"A\"')`\n ",
"xpack.lens.indexPattern.metric.documentation.markdown": "\n返回字段的 {metric}。此函数仅适用于数字字段。\n\n例如:获取价格的 {metric}:\n`{metric}(price)`\n\n例如:获取英国订单价格的 {metric}:\n`{metric}(price, kql='location:UK')`\n ",
"xpack.lens.indexPattern.movingAverage.documentation.markdown": "\n计算随着时间的推移指标的移动平均值,即计算最后 n 个值的平均值以得出当前值。要使用此函数,您还需要配置 Date Histogram 维度。\n默认窗口值为 {defaultValue}。\n\n筛选或排名最前值维度定义的不同序列将分别执行此计算。\n\n取已命名参数 `window`,其指定当前值的平均计算中要包括过去多少个值。\n\n例如:平滑度量线:\n`moving_average(sum(bytes), window=5)`\n ",
- "xpack.lens.indexPattern.now.documentation.markdown": "\n Kibana 中使用的当前时刻,用毫秒 (ms) 表示。\n ",
"xpack.lens.indexPattern.overall_average.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的平均值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或时间间隔函数,则无论使用什么函数,`overall_average` 都将计算所有维度的平均值\n\n例如:与平均值的偏离:\n`sum(bytes) - overall_average(sum(bytes))`\n ",
"xpack.lens.indexPattern.overall_max.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的最大值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或内部函数,则无论使用什么函数,`overall_max` 都将计算所有维度的最大值\n\n例如:范围的百分比\n`(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ",
"xpack.lens.indexPattern.overall_min.documentation.markdown": "\n为当前图表中序列的所有数据点计算指标的最小值。序列由维度使用 Date Histogram 或时间间隔函数定义。\n分解数据的其他维度,如排名最前值或筛选,将被视为不同的序列。\n\n如果当前图表未使用 Date Histogram 或时间间隔函数,则无论使用什么函数,`overall_min` 都将计算所有维度的最小值\n\n例如:范围的百分比\n`(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n ",
@@ -22007,7 +22005,6 @@
"xpack.lens.indexPattern.percentileRanks.documentation.markdown": "\n返回小于某个值的值的百分比。例如,如果某个值大于或等于 95% 的观察值,则称它处于第 95 个百分位等级\n\n例如:获取小于 100 的值的百分比:\n`percentile_rank(bytes, value=100)`\n ",
"xpack.lens.indexPattern.standardDeviation.documentation.markdown": "\n返回字段的变量或差量数量。此函数仅适用于数字字段。\n\n#### 示例\n\n要获取价格的标准偏差,请使用 `standard_deviation(price)`。\n\n要获取来自英国的订单的价格方差,请使用 `square(standard_deviation(price, kql='location:UK'))`。\n ",
"xpack.lens.indexPattern.time_scale.documentation.markdown": "\n\n此高级函数用于将计数和总和标准化为特定时间间隔。它允许集成所存储的已标准化为特定时间间隔的指标。\n\n此函数只能在当前图表中使用了日期直方图函数时使用。\n\n例如:将已标准化指标与其他需要标准化的指标进行比较的比率。\n`normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`\n ",
- "xpack.lens.indexPattern.timeRange.documentation.markdown": "\n指定的时间范围,单位为毫秒 (ms)。\n ",
"xpack.lens.AggBasedLabel": "基于聚合的可视化",
"xpack.lens.app.addToLibrary": "保存到库",
"xpack.lens.app.cancel": "取消",
From 4fc4dfbbda8771e5893c18160ee4238cd7b5f8db Mon Sep 17 00:00:00 2001
From: Melissa Alvarez
Date: Tue, 19 Dec 2023 08:45:52 -0700
Subject: [PATCH 08/95] [ML] Trained models: Adds workflow for creating ingest
pipeline for a trained model (#170902)
## Summary
Related issue: https://github.com/elastic/kibana/issues/168988
This PR adds the ability to create an ingest pipeline using a trained
model for inference.
From within 'Test model' flyout - adds a `Create pipeline` button that
opens another 'Create pipeline' flyout (similar to the DFA models deploy
model flyout).
This flyout utilizes the configuration utilized for testing the model.
### Checklist
Delete any items that are not applicable to this PR.
- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
packages/kbn-doc-links/src/get_doc_links.ts | 1 +
packages/kbn-doc-links/src/types.ts | 1 +
.../add_inference_pipeline_flyout.tsx | 11 +-
.../components/pipeline_details.tsx | 145 +------------
.../components/reindex_with_pipeline.tsx | 13 +-
.../components/ml_inference/get_steps.ts | 11 +-
.../components/ml_inference/validation.ts | 44 +++-
.../add_inference_pipeline_footer.tsx | 14 +-
...dd_inference_pipeline_horizontal_steps.tsx | 111 ++++++----
.../application/components/shared/index.ts | 13 ++
.../on_failure_configuration.tsx | 12 +-
.../shared/pipeline_details_title.tsx | 73 +++++++
.../shared/pipeline_name_and_description.tsx | 115 +++++++++++
.../review_and_create_pipeline.tsx | 48 +++--
.../create_pipeline_for_model_flyout.tsx | 193 ++++++++++++++++++
...ference_properties_from_pipeline_config.ts | 118 +++++++++++
.../get_pipeline_config.ts | 37 ++++
.../pipeline_details.tsx | 183 +++++++++++++++++
.../create_pipeline_for_model/state.ts | 42 ++++
.../test_trained_model.tsx | 79 +++++++
.../model_management/models_list.tsx | 12 +-
.../model_management/test_models/index.ts | 2 +-
.../test_models/models/index_input.tsx | 82 ++++++--
.../test_models/models/inference_base.ts | 18 +-
.../inference_input_form/index_input.tsx | 37 ++--
.../input_form_controls.tsx | 63 ++++++
.../inference_input_form/text_input.tsx | 21 +-
.../test_models/selected_model.tsx | 157 ++++++++++++--
.../test_models/test_flyout.tsx | 136 +++---------
...est_model_and_pipeline_creation_flyout.tsx | 37 ++++
.../test_trained_model_content.tsx | 115 +++++++++++
.../test_trained_models_context.tsx | 32 +++
.../translations/translations/fr-FR.json | 1 -
.../translations/translations/ja-JP.json | 1 -
.../translations/translations/zh-CN.json | 1 -
35 files changed, 1592 insertions(+), 387 deletions(-)
rename x-pack/plugins/ml/public/application/components/{ml_inference/components => shared}/add_inference_pipeline_footer.tsx (88%)
rename x-pack/plugins/ml/public/application/components/{ml_inference/components => shared}/add_inference_pipeline_horizontal_steps.tsx (58%)
create mode 100644 x-pack/plugins/ml/public/application/components/shared/index.ts
rename x-pack/plugins/ml/public/application/components/{ml_inference/components => shared}/on_failure_configuration.tsx (96%)
create mode 100644 x-pack/plugins/ml/public/application/components/shared/pipeline_details_title.tsx
create mode 100644 x-pack/plugins/ml/public/application/components/shared/pipeline_name_and_description.tsx
rename x-pack/plugins/ml/public/application/components/{ml_inference/components => shared}/review_and_create_pipeline.tsx (86%)
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/create_pipeline_for_model_flyout.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_inference_properties_from_pipeline_config.ts
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_pipeline_config.ts
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/pipeline_details.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/state.ts
create mode 100644 x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/test_trained_model.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/input_form_controls.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/test_models/test_model_and_pipeline_creation_flyout.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/test_models/test_trained_model_content.tsx
create mode 100644 x-pack/plugins/ml/public/application/model_management/test_models/test_trained_models_context.tsx
diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts
index 57ae1cc9f6e4a..a259d76c6affb 100644
--- a/packages/kbn-doc-links/src/get_doc_links.ts
+++ b/packages/kbn-doc-links/src/get_doc_links.ts
@@ -671,6 +671,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
cronExpressions: `${ELASTICSEARCH_DOCS}cron-expressions.html`,
executeWatchActionModes: `${ELASTICSEARCH_DOCS}watcher-api-execute-watch.html#watcher-api-execute-watch-action-mode`,
indexExists: `${ELASTICSEARCH_DOCS}indices-exists.html`,
+ inferTrainedModel: `${ELASTICSEARCH_DOCS}infer-trained-model.html`,
multiSearch: `${ELASTICSEARCH_DOCS}search-multi-search.html`,
openIndex: `${ELASTICSEARCH_DOCS}indices-open-close.html`,
putComponentTemplate: `${ELASTICSEARCH_DOCS}indices-component-template.html`,
diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts
index 3b6d22a190244..910c0c218dcc5 100644
--- a/packages/kbn-doc-links/src/types.ts
+++ b/packages/kbn-doc-links/src/types.ts
@@ -391,6 +391,7 @@ export interface DocLinks {
cronExpressions: string;
executeWatchActionModes: string;
indexExists: string;
+ inferTrainedModel: string;
multiSearch: string;
openIndex: string;
putComponentTemplate: string;
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/add_inference_pipeline_flyout.tsx b/x-pack/plugins/ml/public/application/components/ml_inference/add_inference_pipeline_flyout.tsx
index c1e612e3b08d1..e1b4cc2710257 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/add_inference_pipeline_flyout.tsx
+++ b/x-pack/plugins/ml/public/application/components/ml_inference/add_inference_pipeline_flyout.tsx
@@ -22,14 +22,14 @@ import { extractErrorProperties } from '@kbn/ml-error-utils';
import { ModelItem } from '../../model_management/models_list';
import type { AddInferencePipelineSteps } from './types';
import { ADD_INFERENCE_PIPELINE_STEPS } from './constants';
-import { AddInferencePipelineFooter } from './components/add_inference_pipeline_footer';
-import { AddInferencePipelineHorizontalSteps } from './components/add_inference_pipeline_horizontal_steps';
+import { AddInferencePipelineFooter } from '../shared';
+import { AddInferencePipelineHorizontalSteps } from '../shared';
import { getInitialState, getModelType } from './state';
import { PipelineDetails } from './components/pipeline_details';
import { ProcessorConfiguration } from './components/processor_configuration';
-import { OnFailureConfiguration } from './components/on_failure_configuration';
+import { OnFailureConfiguration } from '../shared';
import { TestPipeline } from './components/test_pipeline';
-import { ReviewAndCreatePipeline } from './components/review_and_create_pipeline';
+import { ReviewAndCreatePipeline } from '../shared';
import { useMlApiContext } from '../../contexts/kibana';
import { getPipelineConfig } from './get_pipeline_config';
import { validateInferencePipelineConfigurationStep } from './validation';
@@ -122,6 +122,8 @@ export const AddInferencePipelineFlyout: FC = (
setStep={setStep}
isDetailsStepValid={pipelineNameError === undefined && targetFieldError === undefined}
isConfigureProcessorStepValid={hasUnsavedChanges === false}
+ hasProcessorStep
+ pipelineCreated={formState.pipelineCreated}
/>
{step === ADD_INFERENCE_PIPELINE_STEPS.DETAILS && (
@@ -184,6 +186,7 @@ export const AddInferencePipelineFlyout: FC = (
isConfigureProcessorStepValid={hasUnsavedChanges === false}
pipelineCreated={formState.pipelineCreated}
creatingPipeline={formState.creatingPipeline}
+ hasProcessorStep
/>
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/pipeline_details.tsx b/x-pack/plugins/ml/public/application/components/ml_inference/components/pipeline_details.tsx
index bd36ee4bf6c49..034c6ed5468e6 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/components/pipeline_details.tsx
+++ b/x-pack/plugins/ml/public/application/components/ml_inference/components/pipeline_details.tsx
@@ -14,18 +14,14 @@ import {
EuiFlexItem,
EuiForm,
EuiFormRow,
- EuiLink,
- EuiSpacer,
- EuiTitle,
- EuiText,
- EuiTextArea,
EuiPanel,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
-import { useMlKibana } from '../../../contexts/kibana';
import type { MlInferenceState } from '../types';
+import { PipelineDetailsTitle } from '../../shared';
+import { PipelineNameAndDescription } from '../../shared';
interface Props {
handlePipelineConfigUpdate: (configUpdate: Partial) => void;
@@ -47,12 +43,6 @@ export const PipelineDetails: FC = memo(
targetField,
targetFieldError,
}) => {
- const {
- services: {
- docLinks: { links },
- },
- } = useMlKibana();
-
const handleConfigChange = (value: string, type: string) => {
handlePipelineConfigUpdate({ [type]: value });
};
@@ -60,133 +50,18 @@ export const PipelineDetails: FC = memo(
return (
-
-
- {i18n.translate(
- 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.title',
- { defaultMessage: 'Create a pipeline' }
- )}
-
-
-
-
-
- {modelId},
- pipeline: (
-
- pipeline
-
- ),
- }}
- />
-
-
-
- _reindex API
-
- ),
- pipelineSimulateLink: (
-
- pipeline/_simulate
-
- ),
- }}
- />
-
-
+
- {/* NAME */}
-
- {i18n.translate(
- 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText',
- {
- defaultMessage:
- 'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens.',
- }
- )}
-
- )
- }
- error={pipelineNameError}
- isInvalid={pipelineNameError !== undefined}
- >
- ) =>
- handleConfigChange(e.target.value, 'pipelineName')
- }
- />
-
- {/* DESCRIPTION */}
-
- {i18n.translate(
- 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.description.helpText',
- {
- defaultMessage: 'A description of what this pipeline does.',
- }
- )}
-
- }
- >
- ) =>
- handleConfigChange(e.target.value, 'pipelineDescription')
- }
- />
-
+ {/* NAME and DESCRIPTION */}
+
{/* TARGET FIELD */}
= ({ pipelineName, sourceIndex }) => {
- const [selectedIndex, setSelectedIndex] = useState([
- { label: sourceIndex },
- ]);
+ const [selectedIndex, setSelectedIndex] = useState(
+ sourceIndex ? [{ label: sourceIndex }] : []
+ );
const [options, setOptions] = useState([]);
const [destinationIndex, setDestinationIndex] = useState('');
const [destinationIndexExists, setDestinationIndexExists] = useState(false);
@@ -205,7 +205,7 @@ export const ReindexWithPipeline: FC = ({ pipelineName, sourceIndex }) =>
setCanReindexError(errorMessage);
}
}
- if (hasPrivileges !== undefined) {
+ if (hasPrivileges !== undefined && selectedIndex.length) {
checkPrivileges();
}
},
@@ -264,6 +264,7 @@ export const ReindexWithPipeline: FC = ({ pipelineName, sourceIndex }) =>
0) ||
!canReindex ||
destinationIndexExists
@@ -395,7 +396,7 @@ export const ReindexWithPipeline: FC = ({ pipelineName, sourceIndex }) =>
'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.reindexStartedMessage',
{
defaultMessage: 'Reindexing of {sourceIndex} to {destinationIndex} has started.',
- values: { sourceIndex, destinationIndex },
+ values: { sourceIndex: selectedIndex[0].label, destinationIndex },
}
)}
color="success"
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/get_steps.ts b/x-pack/plugins/ml/public/application/components/ml_inference/get_steps.ts
index a7d3ea17de099..3f7c9ff2255fe 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/get_steps.ts
+++ b/x-pack/plugins/ml/public/application/components/ml_inference/get_steps.ts
@@ -11,7 +11,8 @@ import { ADD_INFERENCE_PIPELINE_STEPS } from './constants';
export function getSteps(
step: AddInferencePipelineSteps,
isConfigureStepValid: boolean,
- isPipelineDataValid: boolean
+ isPipelineDataValid: boolean,
+ hasProcessorStep: boolean
) {
let nextStep: AddInferencePipelineSteps | undefined;
let previousStep: AddInferencePipelineSteps | undefined;
@@ -19,7 +20,9 @@ export function getSteps(
switch (step) {
case ADD_INFERENCE_PIPELINE_STEPS.DETAILS:
- nextStep = ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR;
+ nextStep = hasProcessorStep
+ ? ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR
+ : ADD_INFERENCE_PIPELINE_STEPS.ON_FAILURE;
isContinueButtonEnabled = isConfigureStepValid;
break;
case ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR:
@@ -29,7 +32,9 @@ export function getSteps(
break;
case ADD_INFERENCE_PIPELINE_STEPS.ON_FAILURE:
nextStep = ADD_INFERENCE_PIPELINE_STEPS.TEST;
- previousStep = ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR;
+ previousStep = hasProcessorStep
+ ? ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR
+ : ADD_INFERENCE_PIPELINE_STEPS.DETAILS;
isContinueButtonEnabled = isPipelineDataValid;
break;
case ADD_INFERENCE_PIPELINE_STEPS.TEST:
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/validation.ts b/x-pack/plugins/ml/public/application/components/ml_inference/validation.ts
index f6326669cf55b..8c2e567b1c4f1 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/validation.ts
+++ b/x-pack/plugins/ml/public/application/components/ml_inference/validation.ts
@@ -5,8 +5,10 @@
* 2.0.
*/
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { i18n } from '@kbn/i18n';
import { IngestInferenceProcessor } from '@elastic/elasticsearch/lib/api/types';
+import type { SupportedPytorchTasksType } from '@kbn/ml-trained-models-utils';
import { InferenceModelTypes } from './types';
import type { AddInferencePipelineFormErrors } from './types';
@@ -46,6 +48,18 @@ const INFERENCE_CONFIG_MODEL_TYPE_ERROR = i18n.translate(
defaultMessage: 'Inference configuration inference type must match model type.',
}
);
+const PROCESSOR_REQUIRED = i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.processorRequiredError',
+ {
+ defaultMessage: 'At least one processor is required to create the pipeline.',
+ }
+);
+const INFERENCE_PROCESSOR_REQUIRED = i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.inferenceProcessorRequiredError',
+ {
+ defaultMessage: "An inference processor specifying 'model_id' is required.",
+ }
+);
const VALID_PIPELINE_NAME_REGEX = /^[\w\-]+$/;
export const isValidPipelineName = (input: string): boolean => {
@@ -75,7 +89,7 @@ export const validateInferencePipelineConfigurationStep = (
export const validateInferenceConfig = (
inferenceConfig: IngestInferenceProcessor['inference_config'],
- modelType?: InferenceModelTypes
+ modelType?: InferenceModelTypes | SupportedPytorchTasksType
) => {
const inferenceConfigKeys = Object.keys(inferenceConfig ?? {});
let error;
@@ -116,3 +130,31 @@ export const validateFieldMap = (
return error;
};
+
+export const validatePipelineProcessors = (
+ pipelineProcessors: estypes.IngestPipeline,
+ taskType?: SupportedPytorchTasksType
+) => {
+ const { processors } = pipelineProcessors;
+ let error;
+ // Must have at least one processor
+ if (!Array.isArray(processors) || (Array.isArray(processors) && processors.length < 1)) {
+ error = PROCESSOR_REQUIRED;
+ }
+
+ const inferenceProcessor = processors?.find(
+ (processor) => processor.inference && processor.inference.model_id
+ );
+
+ if (inferenceProcessor === undefined) {
+ error = INFERENCE_PROCESSOR_REQUIRED;
+ } else {
+ // If populated, inference config must have the correct model type
+ const inferenceConfig = inferenceProcessor.inference?.inference_config;
+ if (taskType && inferenceConfig) {
+ error = validateInferenceConfig(inferenceConfig, taskType);
+ }
+ }
+
+ return error;
+};
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_footer.tsx b/x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_footer.tsx
similarity index 88%
rename from x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_footer.tsx
rename to x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_footer.tsx
index 04ea2ea217375..e6d000c4e9531 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_footer.tsx
+++ b/x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_footer.tsx
@@ -9,14 +9,14 @@ import React, { FC, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-import { AddInferencePipelineSteps } from '../types';
+import type { AddInferencePipelineSteps } from '../ml_inference/types';
import {
BACK_BUTTON_LABEL,
CANCEL_BUTTON_LABEL,
CLOSE_BUTTON_LABEL,
CONTINUE_BUTTON_LABEL,
-} from '../constants';
-import { getSteps } from '../get_steps';
+} from '../ml_inference/constants';
+import { getSteps } from '../ml_inference/get_steps';
interface Props {
isDetailsStepValid: boolean;
@@ -26,7 +26,8 @@ interface Props {
step: AddInferencePipelineSteps;
onClose: () => void;
onCreate: () => void;
- setStep: React.Dispatch>;
+ setStep: (step: AddInferencePipelineSteps) => void;
+ hasProcessorStep: boolean;
}
export const AddInferencePipelineFooter: FC = ({
@@ -38,10 +39,11 @@ export const AddInferencePipelineFooter: FC = ({
onCreate,
step,
setStep,
+ hasProcessorStep,
}) => {
const { nextStep, previousStep, isContinueButtonEnabled } = useMemo(
- () => getSteps(step, isDetailsStepValid, isConfigureProcessorStepValid),
- [isDetailsStepValid, isConfigureProcessorStepValid, step]
+ () => getSteps(step, isDetailsStepValid, isConfigureProcessorStepValid, hasProcessorStep),
+ [isDetailsStepValid, isConfigureProcessorStepValid, step, hasProcessorStep]
);
return (
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx b/x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_horizontal_steps.tsx
similarity index 58%
rename from x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx
rename to x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_horizontal_steps.tsx
index 2a34f6483c24d..c8cdf387c84c2 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/components/add_inference_pipeline_horizontal_steps.tsx
+++ b/x-pack/plugins/ml/public/application/components/shared/add_inference_pipeline_horizontal_steps.tsx
@@ -8,58 +8,58 @@
import React, { FC, memo } from 'react';
import { i18n } from '@kbn/i18n';
-import { EuiStepsHorizontal, EuiStepsHorizontalProps } from '@elastic/eui';
-import type { AddInferencePipelineSteps } from '../types';
-import { ADD_INFERENCE_PIPELINE_STEPS } from '../constants';
+import { EuiStepsHorizontal, type EuiStepsHorizontalProps } from '@elastic/eui';
+import type { AddInferencePipelineSteps } from '../ml_inference/types';
+import { ADD_INFERENCE_PIPELINE_STEPS } from '../ml_inference/constants';
const steps = Object.values(ADD_INFERENCE_PIPELINE_STEPS);
interface Props {
step: AddInferencePipelineSteps;
- setStep: React.Dispatch>;
+ setStep: (step: AddInferencePipelineSteps) => void;
isDetailsStepValid: boolean;
- isConfigureProcessorStepValid: boolean;
+ isConfigureProcessorStepValid?: boolean;
+ hasProcessorStep: boolean;
+ pipelineCreated: boolean;
}
+const DISABLED = 'disabled';
+const COMPLETE = 'complete';
+const INCOMPLETE = 'incomplete';
+
export const AddInferencePipelineHorizontalSteps: FC = memo(
- ({ step, setStep, isDetailsStepValid, isConfigureProcessorStepValid }) => {
+ ({
+ step,
+ setStep,
+ isDetailsStepValid,
+ isConfigureProcessorStepValid,
+ hasProcessorStep,
+ pipelineCreated,
+ }) => {
const currentStepIndex = steps.findIndex((s) => s === step);
+
const navSteps: EuiStepsHorizontalProps['steps'] = [
{
// Details
- onClick: () => setStep(ADD_INFERENCE_PIPELINE_STEPS.DETAILS),
- status: isDetailsStepValid ? 'complete' : 'incomplete',
- title: i18n.translate(
- 'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.details.title',
- {
- defaultMessage: 'Details',
- }
- ),
- },
- {
- // Processor configuration
onClick: () => {
- if (!isDetailsStepValid) return;
- setStep(ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR);
+ if (pipelineCreated) return;
+ setStep(ADD_INFERENCE_PIPELINE_STEPS.DETAILS);
},
- status:
- isDetailsStepValid && isConfigureProcessorStepValid && currentStepIndex > 1
- ? 'complete'
- : 'incomplete',
+ status: isDetailsStepValid ? COMPLETE : INCOMPLETE,
title: i18n.translate(
- 'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.configureProcessor.title',
+ 'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.details.title',
{
- defaultMessage: 'Configure processor',
+ defaultMessage: 'Details',
}
),
},
{
- // handle failures
+ // Handle failures
onClick: () => {
- if (!isDetailsStepValid) return;
+ if (!isDetailsStepValid || pipelineCreated) return;
setStep(ADD_INFERENCE_PIPELINE_STEPS.ON_FAILURE);
},
- status: currentStepIndex > 2 ? 'complete' : 'incomplete',
+ status: currentStepIndex > 2 ? COMPLETE : INCOMPLETE,
title: i18n.translate(
'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.handleFailures.title',
{
@@ -70,10 +70,10 @@ export const AddInferencePipelineHorizontalSteps: FC = memo(
{
// Test
onClick: () => {
- if (!isConfigureProcessorStepValid || !isDetailsStepValid) return;
+ if (!isConfigureProcessorStepValid || !isDetailsStepValid || pipelineCreated) return;
setStep(ADD_INFERENCE_PIPELINE_STEPS.TEST);
},
- status: currentStepIndex > 3 ? 'complete' : 'incomplete',
+ status: currentStepIndex > 3 ? COMPLETE : INCOMPLETE,
title: i18n.translate(
'xpack.ml.trainedModels.content.indices.transforms.addInferencePipelineModal.steps.test.title',
{
@@ -84,10 +84,10 @@ export const AddInferencePipelineHorizontalSteps: FC = memo(
{
// Review and Create
onClick: () => {
- if (!isConfigureProcessorStepValid) return;
+ if (!isConfigureProcessorStepValid || pipelineCreated) return;
setStep(ADD_INFERENCE_PIPELINE_STEPS.CREATE);
},
- status: isDetailsStepValid && isConfigureProcessorStepValid ? 'incomplete' : 'disabled',
+ status: isDetailsStepValid && isConfigureProcessorStepValid ? INCOMPLETE : DISABLED,
title: i18n.translate(
'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.create.title',
{
@@ -96,23 +96,60 @@ export const AddInferencePipelineHorizontalSteps: FC = memo(
),
},
];
+
+ if (hasProcessorStep === true) {
+ navSteps.splice(1, 0, {
+ // Processor configuration
+ onClick: () => {
+ if (!isDetailsStepValid || pipelineCreated) return;
+ setStep(ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR);
+ },
+ status:
+ isDetailsStepValid && isConfigureProcessorStepValid && currentStepIndex > 1
+ ? COMPLETE
+ : INCOMPLETE,
+ title: i18n.translate(
+ 'xpack.ml.inferencePipeline.content.indices.transforms.addInferencePipelineModal.steps.configureProcessor.title',
+ {
+ defaultMessage: 'Configure processor',
+ }
+ ),
+ });
+ }
+ let DETAILS_INDEX: number;
+ let CONFIGURE_INDEX: number | undefined;
+ let ON_FAILURE_INDEX: number;
+ let TEST_INDEX: number;
+ let CREATE_INDEX: number;
+
+ if (hasProcessorStep) {
+ [DETAILS_INDEX, CONFIGURE_INDEX, ON_FAILURE_INDEX, TEST_INDEX, CREATE_INDEX] = [
+ 0, 1, 2, 3, 4, 5,
+ ];
+ } else {
+ [DETAILS_INDEX, ON_FAILURE_INDEX, TEST_INDEX, CREATE_INDEX] = [0, 1, 2, 3, 4];
+ }
+
switch (step) {
case ADD_INFERENCE_PIPELINE_STEPS.DETAILS:
- navSteps[0].status = 'current';
+ navSteps[DETAILS_INDEX].status = 'current';
break;
case ADD_INFERENCE_PIPELINE_STEPS.CONFIGURE_PROCESSOR:
- navSteps[1].status = 'current';
+ if (CONFIGURE_INDEX !== undefined) {
+ navSteps[CONFIGURE_INDEX].status = 'current';
+ }
break;
case ADD_INFERENCE_PIPELINE_STEPS.ON_FAILURE:
- navSteps[2].status = 'current';
+ navSteps[ON_FAILURE_INDEX].status = 'current';
break;
case ADD_INFERENCE_PIPELINE_STEPS.TEST:
- navSteps[3].status = 'current';
+ navSteps[TEST_INDEX].status = 'current';
break;
case ADD_INFERENCE_PIPELINE_STEPS.CREATE:
- navSteps[4].status = 'current';
+ navSteps[CREATE_INDEX].status = 'current';
break;
}
+
return ;
}
);
diff --git a/x-pack/plugins/ml/public/application/components/shared/index.ts b/x-pack/plugins/ml/public/application/components/shared/index.ts
new file mode 100644
index 0000000000000..573c13257a465
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/components/shared/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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+export { AddInferencePipelineHorizontalSteps } from './add_inference_pipeline_horizontal_steps';
+export { AddInferencePipelineFooter } from './add_inference_pipeline_footer';
+export { ReviewAndCreatePipeline } from './review_and_create_pipeline';
+export { OnFailureConfiguration } from './on_failure_configuration';
+export { PipelineDetailsTitle } from './pipeline_details_title';
+export { PipelineNameAndDescription } from './pipeline_name_and_description';
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/on_failure_configuration.tsx b/x-pack/plugins/ml/public/application/components/shared/on_failure_configuration.tsx
similarity index 96%
rename from x-pack/plugins/ml/public/application/components/ml_inference/components/on_failure_configuration.tsx
rename to x-pack/plugins/ml/public/application/components/shared/on_failure_configuration.tsx
index f53e80b122f53..10ab5a46a6327 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/components/on_failure_configuration.tsx
+++ b/x-pack/plugins/ml/public/application/components/shared/on_failure_configuration.tsx
@@ -25,12 +25,12 @@ import { CodeEditor } from '@kbn/kibana-react-plugin/public';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
-import { SaveChangesButton } from './save_changes_button';
-import type { MlInferenceState } from '../types';
-import { getDefaultOnFailureConfiguration } from '../state';
-import { CANCEL_EDIT_MESSAGE, EDIT_MESSAGE } from '../constants';
-import { useMlKibana } from '../../../contexts/kibana';
-import { isValidJson } from '../../../../../common/util/validation_utils';
+import { SaveChangesButton } from '../ml_inference/components/save_changes_button';
+import type { MlInferenceState } from '../ml_inference/types';
+import { getDefaultOnFailureConfiguration } from '../ml_inference/state';
+import { CANCEL_EDIT_MESSAGE, EDIT_MESSAGE } from '../ml_inference/constants';
+import { useMlKibana } from '../../contexts/kibana';
+import { isValidJson } from '../../../../common/util/validation_utils';
interface Props {
handleAdvancedConfigUpdate: (configUpdate: Partial) => void;
diff --git a/x-pack/plugins/ml/public/application/components/shared/pipeline_details_title.tsx b/x-pack/plugins/ml/public/application/components/shared/pipeline_details_title.tsx
new file mode 100644
index 0000000000000..ce7ef231256c5
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/components/shared/pipeline_details_title.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { FC } from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n-react';
+import { EuiCode, EuiLink, EuiSpacer, EuiTitle, EuiText } from '@elastic/eui';
+
+import { useMlKibana } from '../../contexts/kibana';
+
+interface Props {
+ modelId: string;
+}
+
+export const PipelineDetailsTitle: FC = ({ modelId }) => {
+ const {
+ services: {
+ docLinks: { links },
+ },
+ } = useMlKibana();
+
+ return (
+ <>
+
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.title',
+ { defaultMessage: 'Create a pipeline' }
+ )}
+
+
+
+
+
+ {modelId},
+ pipeline: (
+
+ pipeline
+
+ ),
+ }}
+ />
+
+
+
+ _reindex API
+
+ ),
+ pipelineSimulateLink: (
+
+ pipeline/_simulate
+
+ ),
+ }}
+ />
+
+
+ >
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/components/shared/pipeline_name_and_description.tsx b/x-pack/plugins/ml/public/application/components/shared/pipeline_name_and_description.tsx
new file mode 100644
index 0000000000000..c64fbca939034
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/components/shared/pipeline_name_and_description.tsx
@@ -0,0 +1,115 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { FC } from 'react';
+import { i18n } from '@kbn/i18n';
+import { EuiFieldText, EuiFormRow, EuiText, EuiTextArea } from '@elastic/eui';
+
+interface Props {
+ handlePipelineConfigUpdate: (configUpdate: Partial) => void;
+ pipelineNameError: string | undefined;
+ pipelineDescription: string;
+ pipelineName: string;
+}
+
+export const PipelineNameAndDescription: FC = ({
+ pipelineName,
+ pipelineNameError,
+ pipelineDescription,
+ handlePipelineConfigUpdate,
+}) => {
+ const handleConfigChange = (value: string, type: string) => {
+ handlePipelineConfigUpdate({ [type]: value });
+ };
+
+ return (
+ <>
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.name.helpText',
+ {
+ defaultMessage:
+ 'Pipeline names are unique within a deployment and can only contain letters, numbers, underscores, and hyphens.',
+ }
+ )}
+
+ )
+ }
+ error={pipelineNameError}
+ isInvalid={pipelineNameError !== undefined}
+ >
+ ) =>
+ handleConfigChange(e.target.value, 'pipelineName')
+ }
+ />
+
+ {/* DESCRIPTION */}
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.configure.description.helpText',
+ {
+ defaultMessage: 'A description of the pipeline.',
+ }
+ )}
+
+ }
+ >
+ ) =>
+ handleConfigChange(e.target.value, 'pipelineDescription')
+ }
+ />
+
+ >
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/components/ml_inference/components/review_and_create_pipeline.tsx b/x-pack/plugins/ml/public/application/components/shared/review_and_create_pipeline.tsx
similarity index 86%
rename from x-pack/plugins/ml/public/application/components/ml_inference/components/review_and_create_pipeline.tsx
rename to x-pack/plugins/ml/public/application/components/shared/review_and_create_pipeline.tsx
index d80e678bafb06..7cb3066436af9 100644
--- a/x-pack/plugins/ml/public/application/components/ml_inference/components/review_and_create_pipeline.tsx
+++ b/x-pack/plugins/ml/public/application/components/shared/review_and_create_pipeline.tsx
@@ -7,6 +7,7 @@
import React, { FC, useMemo, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
EuiAccordion,
@@ -18,17 +19,28 @@ import {
EuiSpacer,
EuiTitle,
EuiText,
+ EuiTextColor,
htmlIdGenerator,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { IngestPipeline } from '@elastic/elasticsearch/lib/api/types';
-import { useMlKibana } from '../../../contexts/kibana';
-import { ReindexWithPipeline } from './reindex_with_pipeline';
+import { useMlKibana } from '../../contexts/kibana';
+import { ReindexWithPipeline } from '../ml_inference/components/reindex_with_pipeline';
const MANAGEMENT_APP_ID = 'management';
+function getFieldFromPipelineConfig(config: estypes.IngestPipeline) {
+ const { processors } = config;
+ let field = '';
+ if (processors?.length) {
+ field = Object.keys(processors[0].inference?.field_map ?? {})[0];
+ }
+ return field;
+}
+
interface Props {
+ highlightTargetField?: boolean;
inferencePipeline: IngestPipeline;
modelType?: string;
pipelineName: string;
@@ -38,6 +50,7 @@ interface Props {
}
export const ReviewAndCreatePipeline: FC = ({
+ highlightTargetField = false,
inferencePipeline,
modelType,
pipelineName,
@@ -62,6 +75,10 @@ export const ReviewAndCreatePipeline: FC = ({
: links.ingest.inferenceClassification;
const accordionId = useMemo(() => htmlIdGenerator()(), []);
+ const targetedField = useMemo(
+ () => getFieldFromPipelineConfig(inferencePipeline),
+ [inferencePipeline]
+ );
const configCodeBlock = useMemo(
() => (
@@ -84,7 +101,7 @@ export const ReviewAndCreatePipeline: FC = ({
gutterSize="s"
data-test-subj="mlTrainedModelsInferenceReviewAndCreateStep"
>
-
+
{pipelineCreated === false ? (
@@ -189,20 +206,19 @@ export const ReviewAndCreatePipeline: FC = ({
) : null}
>
-
-
-
- {!pipelineCreated ? (
-
- ) : null}
-
-
-
+ {highlightTargetField ? (
+
+
+ {targetedField} }}
+ />
+
+
+ ) : null}
- {pipelineCreated && sourceIndex ? (
+ {pipelineCreated ? (
<>
void;
+ model: ModelItem;
+}
+
+export const CreatePipelineForModelFlyout: FC = ({
+ onClose,
+ model,
+}) => {
+ const {
+ currentContext: { pipelineConfig },
+ } = useTestTrainedModelsContext();
+
+ const initialState = useMemo(
+ () => getInitialState(model, pipelineConfig),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [model.model_id, pipelineConfig]
+ );
+ const [formState, setFormState] = useState(initialState);
+ const [step, setStep] = useState(ADD_INFERENCE_PIPELINE_STEPS.DETAILS);
+ const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
+ const taskType = useMemo(
+ () => Object.keys(model.inference_config ?? {})[0],
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [model.model_id]
+ ) as SupportedPytorchTasksType;
+
+ const {
+ trainedModels: { createInferencePipeline },
+ } = useMlApiContext();
+
+ const createPipeline = async () => {
+ setFormState({ ...formState, creatingPipeline: true });
+ try {
+ const config = getPipelineConfig(formState);
+ await createInferencePipeline(formState.pipelineName, config);
+ setFormState({
+ ...formState,
+ pipelineCreated: true,
+ creatingPipeline: false,
+ pipelineError: undefined,
+ });
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.error(e);
+ const errorProperties = extractErrorProperties(e);
+ setFormState({
+ ...formState,
+ creatingPipeline: false,
+ pipelineError: errorProperties.message ?? e.message,
+ });
+ }
+ };
+
+ const pipelineNames = useFetchPipelines();
+
+ const handleConfigUpdate = (configUpdate: Partial) => {
+ const updatedState = { ...formState, ...configUpdate };
+ setFormState(updatedState);
+ };
+
+ const handleSetStep = (currentStep: AddInferencePipelineSteps) => {
+ setStep(currentStep);
+ };
+
+ const { pipelineName: pipelineNameError } = useMemo(() => {
+ const errors = validateInferencePipelineConfigurationStep(
+ formState.pipelineName,
+ pipelineNames
+ );
+ return errors;
+ }, [pipelineNames, formState.pipelineName]);
+
+ return (
+
+
+
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.createInferencePipeline.title',
+ {
+ defaultMessage: 'Create inference pipeline',
+ }
+ )}
+
+
+
+
+
+
+ {step === ADD_INFERENCE_PIPELINE_STEPS.DETAILS && (
+
+ )}
+ {step === ADD_INFERENCE_PIPELINE_STEPS.ON_FAILURE && (
+
+ )}
+ {step === ADD_INFERENCE_PIPELINE_STEPS.TEST && (
+
+ )}
+ {step === ADD_INFERENCE_PIPELINE_STEPS.CREATE && (
+
+ )}
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_inference_properties_from_pipeline_config.ts b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_inference_properties_from_pipeline_config.ts
new file mode 100644
index 0000000000000..68b7dcda61a73
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_inference_properties_from_pipeline_config.ts
@@ -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 * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import {
+ IngestInferenceProcessor,
+ IngestInferenceConfig,
+} from '@elastic/elasticsearch/lib/api/types';
+import { isPopulatedObject } from '@kbn/ml-is-populated-object';
+import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils';
+import { DEFAULT_INPUT_FIELD } from '../test_models/models/inference_base';
+
+const INPUT_FIELD = 'inputField';
+const ZERO_SHOT_CLASSIFICATION_PROPERTIES = ['labels', 'multi_label'] as const;
+const QUESTION_ANSWERING_PROPERTIES = ['question'] as const;
+
+const MODEL_INFERENCE_CONFIG_PROPERTIES = {
+ [SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING]: QUESTION_ANSWERING_PROPERTIES,
+ [SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION]: ZERO_SHOT_CLASSIFICATION_PROPERTIES,
+} as const;
+
+type SupportedModelInferenceConfigPropertiesType = keyof typeof MODEL_INFERENCE_CONFIG_PROPERTIES;
+
+interface MLIngestInferenceProcessor extends IngestInferenceProcessor {
+ inference_config: MLInferencePipelineInferenceConfig;
+}
+
+// Currently, estypes doesn't include pipeline processor types with the trained model processors
+type MLInferencePipelineInferenceConfig = IngestInferenceConfig & {
+ zero_shot_classification?: estypes.MlZeroShotClassificationInferenceOptions;
+ question_answering?: estypes.MlQuestionAnsweringInferenceUpdateOptions;
+};
+
+interface GetInferencePropertiesFromPipelineConfigReturnType {
+ inputField: string;
+ inferenceConfig?: MLInferencePipelineInferenceConfig;
+ inferenceObj?: IngestInferenceProcessor | MLIngestInferenceProcessor;
+ fieldMap?: IngestInferenceProcessor['field_map'];
+ labels?: string[];
+ multi_label?: boolean;
+ question?: string;
+}
+
+function isSupportedInferenceConfigPropertyType(
+ arg: unknown
+): arg is SupportedModelInferenceConfigPropertiesType {
+ return typeof arg === 'string' && Object.keys(MODEL_INFERENCE_CONFIG_PROPERTIES).includes(arg);
+}
+
+export function isMlInferencePipelineInferenceConfig(
+ arg: unknown
+): arg is MLInferencePipelineInferenceConfig {
+ return (
+ isPopulatedObject(arg, [SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING]) ||
+ isPopulatedObject(arg, [SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION])
+ );
+}
+
+export function isMlIngestInferenceProcessor(arg: unknown): arg is MLIngestInferenceProcessor {
+ return (
+ isPopulatedObject(arg) &&
+ arg.hasOwnProperty('inference_config') &&
+ (isPopulatedObject(arg.inference_config, [SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING]) ||
+ isPopulatedObject(arg.inference_config, [SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION]))
+ );
+}
+
+export function getInferencePropertiesFromPipelineConfig(
+ type: string,
+ pipelineConfig: estypes.IngestPipeline
+): GetInferencePropertiesFromPipelineConfigReturnType {
+ const propertiesToReturn: GetInferencePropertiesFromPipelineConfigReturnType = {
+ [INPUT_FIELD]: '',
+ };
+
+ pipelineConfig.processors?.forEach((processor) => {
+ const { inference } = processor;
+ if (inference) {
+ propertiesToReturn.inferenceObj = inference;
+ // Get the input field
+ if (inference.field_map) {
+ propertiesToReturn.fieldMap = inference.field_map;
+
+ for (const [key, value] of Object.entries(inference.field_map)) {
+ if (value === DEFAULT_INPUT_FIELD) {
+ propertiesToReturn[INPUT_FIELD] = key;
+ }
+ }
+ if (propertiesToReturn[INPUT_FIELD] === '') {
+ // If not found, set to the first field in the field map
+ propertiesToReturn[INPUT_FIELD] = Object.keys(inference.field_map)[0];
+ }
+ }
+ propertiesToReturn.inferenceConfig = inference.inference_config;
+ // Get the properties associated with the type of model/task
+ if (
+ isMlInferencePipelineInferenceConfig(propertiesToReturn.inferenceConfig) &&
+ isSupportedInferenceConfigPropertyType(type)
+ ) {
+ MODEL_INFERENCE_CONFIG_PROPERTIES[type]?.forEach((property) => {
+ const configSettings =
+ propertiesToReturn.inferenceConfig && propertiesToReturn.inferenceConfig[type];
+ propertiesToReturn[property] =
+ configSettings && configSettings.hasOwnProperty(property)
+ ? // @ts-ignore
+ configSettings[property]
+ : undefined;
+ });
+ }
+ }
+ });
+
+ return propertiesToReturn;
+}
diff --git a/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_pipeline_config.ts b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_pipeline_config.ts
new file mode 100644
index 0000000000000..10c405090f057
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/get_pipeline_config.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import type { InferecePipelineCreationState } from './state';
+
+export function getPipelineConfig(state: InferecePipelineCreationState): estypes.IngestPipeline {
+ const { ignoreFailure, modelId, onFailure, pipelineDescription, initialPipelineConfig } = state;
+ const processor =
+ initialPipelineConfig?.processors && initialPipelineConfig.processors?.length
+ ? initialPipelineConfig?.processors[0]
+ : {};
+
+ return {
+ description: pipelineDescription,
+ processors: [
+ {
+ inference: {
+ ...(processor?.inference
+ ? {
+ ...processor.inference,
+ ignore_failure: ignoreFailure,
+ ...(onFailure && Object.keys(onFailure).length > 0
+ ? { on_failure: onFailure }
+ : { on_failure: undefined }),
+ }
+ : {}),
+ model_id: modelId,
+ },
+ },
+ ],
+ };
+}
diff --git a/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/pipeline_details.tsx b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/pipeline_details.tsx
new file mode 100644
index 0000000000000..ef474ce3b4345
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/pipeline_details.tsx
@@ -0,0 +1,183 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor 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, { FC, memo, useState } from 'react';
+
+import {
+ EuiButtonEmpty,
+ EuiCodeBlock,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiForm,
+ EuiFormRow,
+ EuiPanel,
+} from '@elastic/eui';
+
+import { i18n } from '@kbn/i18n';
+import { CodeEditor } from '@kbn/kibana-react-plugin/public';
+import type { SupportedPytorchTasksType } from '@kbn/ml-trained-models-utils';
+import { type InferecePipelineCreationState } from './state';
+import { EDIT_MESSAGE, CANCEL_EDIT_MESSAGE } from '../../components/ml_inference/constants';
+import { isValidJson } from '../../../../common/util/validation_utils';
+import { useTestTrainedModelsContext } from '../test_models/test_trained_models_context';
+import { SaveChangesButton } from '../../components/ml_inference/components/save_changes_button';
+import { validatePipelineProcessors } from '../../components/ml_inference/validation';
+import { PipelineDetailsTitle, PipelineNameAndDescription } from '../../components/shared';
+
+interface Props {
+ handlePipelineConfigUpdate: (configUpdate: Partial) => void;
+ modelId: string;
+ pipelineNameError: string | undefined;
+ pipelineName: string;
+ pipelineDescription: string;
+ initialPipelineConfig?: InferecePipelineCreationState['initialPipelineConfig'];
+ setHasUnsavedChanges: React.Dispatch>;
+ taskType?: SupportedPytorchTasksType;
+}
+
+export const PipelineDetails: FC = memo(
+ ({
+ handlePipelineConfigUpdate,
+ modelId,
+ pipelineName,
+ pipelineNameError,
+ pipelineDescription,
+ initialPipelineConfig,
+ setHasUnsavedChanges,
+ taskType,
+ }) => {
+ const [isProcessorConfigValid, setIsProcessorConfigValid] = useState(true);
+ const [processorConfigError, setProcessorConfigError] = useState();
+
+ const {
+ currentContext: { pipelineConfig },
+ } = useTestTrainedModelsContext();
+ const [processorConfigString, setProcessorConfigString] = useState(
+ JSON.stringify(initialPipelineConfig ?? {}, null, 2)
+ );
+ const [editProcessorConfig, setEditProcessorConfig] = useState(false);
+
+ const updateProcessorConfig = () => {
+ const invalidProcessorConfigMessage = validatePipelineProcessors(
+ JSON.parse(processorConfigString),
+ taskType
+ );
+ if (invalidProcessorConfigMessage === undefined) {
+ handlePipelineConfigUpdate({ initialPipelineConfig: JSON.parse(processorConfigString) });
+ setHasUnsavedChanges(false);
+ setEditProcessorConfig(false);
+ setProcessorConfigError(undefined);
+ } else {
+ setHasUnsavedChanges(true);
+ setIsProcessorConfigValid(false);
+ setProcessorConfigError(invalidProcessorConfigMessage);
+ }
+ };
+
+ const handleProcessorConfigChange = (json: string) => {
+ setProcessorConfigString(json);
+ const valid = isValidJson(json);
+ setIsProcessorConfigValid(valid);
+ };
+
+ const resetProcessorConfig = () => {
+ setProcessorConfigString(JSON.stringify(pipelineConfig, null, 2));
+ setIsProcessorConfigValid(true);
+ setProcessorConfigError(undefined);
+ };
+
+ return (
+
+
+
+
+
+
+ {/* NAME */}
+
+ {/* NAME and DESCRIPTION */}
+
+ {/* PROCESSOR CONFIGURATION */}
+
+
+ {
+ const editingState = !editProcessorConfig;
+ if (editingState === false) {
+ setProcessorConfigError(undefined);
+ setIsProcessorConfigValid(true);
+ setHasUnsavedChanges(false);
+ }
+ setEditProcessorConfig(editingState);
+ }}
+ >
+ {editProcessorConfig ? CANCEL_EDIT_MESSAGE : EDIT_MESSAGE}
+
+
+
+ {editProcessorConfig ? (
+
+ ) : null}
+
+
+ {editProcessorConfig ? (
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.advanced.resetInferenceConfigButton',
+ { defaultMessage: 'Reset' }
+ )}
+
+ ) : null}
+
+
+ }
+ error={processorConfigError}
+ isInvalid={processorConfigError !== undefined}
+ data-test-subj="mlTrainedModelsInferencePipelineInferenceConfigEditor"
+ >
+ {editProcessorConfig ? (
+
+ ) : (
+
+ {processorConfigString}
+
+ )}
+
+
+
+
+
+ );
+ }
+);
diff --git a/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/state.ts b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/state.ts
new file mode 100644
index 0000000000000..9edcb19e61e38
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/state.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { IngestInferenceProcessor } from '@elastic/elasticsearch/lib/api/types';
+import { getDefaultOnFailureConfiguration } from '../../components/ml_inference/state';
+import type { ModelItem } from '../models_list';
+
+export interface InferecePipelineCreationState {
+ creatingPipeline: boolean;
+ error: boolean;
+ ignoreFailure: boolean;
+ modelId: string;
+ onFailure?: IngestInferenceProcessor['on_failure'];
+ pipelineName: string;
+ pipelineNameError?: string;
+ pipelineDescription: string;
+ pipelineCreated: boolean;
+ pipelineError?: string;
+ initialPipelineConfig?: estypes.IngestPipeline;
+ takeActionOnFailure: boolean;
+}
+
+export const getInitialState = (
+ model: ModelItem,
+ initialPipelineConfig: estypes.IngestPipeline | undefined
+): InferecePipelineCreationState => ({
+ creatingPipeline: false,
+ error: false,
+ ignoreFailure: false,
+ modelId: model.model_id,
+ onFailure: getDefaultOnFailureConfiguration(),
+ pipelineDescription: `Uses the pre-trained model ${model.model_id} to infer against the data that is being ingested in the pipeline`,
+ pipelineName: `ml-inference-${model.model_id}`,
+ pipelineCreated: false,
+ initialPipelineConfig,
+ takeActionOnFailure: true,
+});
diff --git a/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/test_trained_model.tsx b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/test_trained_model.tsx
new file mode 100644
index 0000000000000..5f793fa84801e
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/create_pipeline_for_model/test_trained_model.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor 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, { FC } from 'react';
+import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n-react';
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+
+import { ModelItem } from '../models_list';
+import { TestTrainedModelContent } from '../test_models/test_trained_model_content';
+import { useMlKibana } from '../../contexts/kibana';
+import { type InferecePipelineCreationState } from './state';
+
+interface ContentProps {
+ model: ModelItem;
+ handlePipelineConfigUpdate: (configUpdate: Partial) => void;
+ externalPipelineConfig?: estypes.IngestPipeline;
+}
+
+export const TestTrainedModel: FC = ({
+ model,
+ handlePipelineConfigUpdate,
+ externalPipelineConfig,
+}) => {
+ const {
+ services: {
+ docLinks: { links },
+ },
+ } = useMlKibana();
+
+ return (
+
+
+
+
+ {i18n.translate(
+ 'xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.advanced.testTrainedModelTitle',
+ { defaultMessage: 'Try it out' }
+ )}
+
+
+
+
+
+
+
+
+
+ Learn more.
+
+ ),
+ }}
+ />
+
+
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx
index 0aebca5c1673c..dd766d10c36d1 100644
--- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx
@@ -69,7 +69,7 @@ import { useToastNotificationService } from '../services/toast_notification_serv
import { useFieldFormatter } from '../contexts/kibana/use_field_formatter';
import { useRefresh } from '../routing/use_refresh';
import { SavedObjectsWarning } from '../components/saved_objects_warning';
-import { TestTrainedModelFlyout } from './test_models';
+import { TestModelAndPipelineCreationFlyout } from './test_models';
import { TestDfaModelsFlyout } from './test_dfa_models_flyout';
import { AddInferencePipelineFlyout } from '../components/ml_inference';
import { useEnabledFeatures } from '../contexts/ml';
@@ -819,7 +819,15 @@ export const ModelsList: FC = ({
/>
)}
{modelToTest === null ? null : (
-
+ {
+ setModelToTest(null);
+ if (refreshList) {
+ fetchModelsData();
+ }
+ }}
+ />
)}
{dfaModelToTest === null ? null : (
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/index.ts b/x-pack/plugins/ml/public/application/model_management/test_models/index.ts
index 25078a40d4206..4b238f477092e 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/index.ts
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/index.ts
@@ -5,5 +5,5 @@
* 2.0.
*/
-export { TestTrainedModelFlyout } from './test_flyout';
+export { TestModelAndPipelineCreationFlyout } from './test_model_and_pipeline_creation_flyout';
export { isTestable, isDfaTrainedModel } from './utils';
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/index_input.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/models/index_input.tsx
index 03466cd87a16b..3ae11845646ad 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/models/index_input.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/index_input.tsx
@@ -10,7 +10,15 @@ import React, { FC, useState, useMemo, useEffect, useCallback } from 'react';
import useObservable from 'react-use/lib/useObservable';
import { firstValueFrom } from 'rxjs';
import { DataView } from '@kbn/data-views-plugin/common';
-import { EuiSpacer, EuiSelect, EuiFormRow, EuiAccordion, EuiCodeBlock } from '@elastic/eui';
+import {
+ EuiAccordion,
+ EuiCode,
+ EuiCodeBlock,
+ EuiFormRow,
+ EuiSpacer,
+ EuiSelect,
+ EuiText,
+} from '@elastic/eui';
import { isPopulatedObject } from '@kbn/ml-is-populated-object';
import { i18n } from '@kbn/i18n';
@@ -21,9 +29,14 @@ import type { InferrerType } from '.';
interface Props {
inferrer: InferrerType;
data: ReturnType;
+ disableIndexSelection: boolean;
}
-export const InferenceInputFormIndexControls: FC = ({ inferrer, data }) => {
+export const InferenceInputFormIndexControls: FC = ({
+ inferrer,
+ data,
+ disableIndexSelection,
+}) => {
const {
dataViewListItems,
fieldNames,
@@ -40,14 +53,25 @@ export const InferenceInputFormIndexControls: FC = ({ inferrer, data }) =
return (
<>
- setSelectedDataViewId(e.target.value)}
- hasNoInitialSelection={true}
- disabled={runningState === RUNNING_STATE.RUNNING}
- fullWidth
- />
+ {disableIndexSelection ? (
+
+
+ {dataViewListItems.find((item) => item.value === selectedDataViewId)?.text}
+
+
+ ) : (
+ {
+ inferrer.setSelectedDataViewId(e.target.value);
+ setSelectedDataViewId(e.target.value);
+ }}
+ hasNoInitialSelection={true}
+ disabled={runningState === RUNNING_STATE.RUNNING}
+ fullWidth
+ />
+ )}
= ({ inferrer, data }) =
setSelectedField(e.target.value)}
+ onChange={(e) => {
+ setSelectedField(e.target.value);
+ }}
hasNoInitialSelection={true}
disabled={runningState === RUNNING_STATE.RUNNING}
fullWidth
@@ -79,7 +105,14 @@ export const InferenceInputFormIndexControls: FC = ({ inferrer, data }) =
}
)}
>
-
+
{JSON.stringify(pipeline, null, 2)}
@@ -87,7 +120,13 @@ export const InferenceInputFormIndexControls: FC = ({ inferrer, data }) =
);
};
-export function useIndexInput({ inferrer }: { inferrer: InferrerType }) {
+export function useIndexInput({
+ inferrer,
+ defaultSelectedDataViewId,
+}: {
+ inferrer: InferrerType;
+ defaultSelectedDataViewId?: string;
+}) {
const {
services: {
data: {
@@ -100,7 +139,9 @@ export function useIndexInput({ inferrer }: { inferrer: InferrerType }) {
const [dataViewListItems, setDataViewListItems] = useState<
Array<{ value: string; text: string }>
>([]);
- const [selectedDataViewId, setSelectedDataViewId] = useState(undefined);
+ const [selectedDataViewId, setSelectedDataViewId] = useState(
+ defaultSelectedDataViewId
+ );
const [selectedDataView, setSelectedDataView] = useState(null);
const [fieldNames, setFieldNames] = useState>([]);
const selectedField = useObservable(inferrer.getInputField$(), inferrer.getInputField());
@@ -197,11 +238,20 @@ export function useIndexInput({ inferrer }: { inferrer: InferrerType }) {
}));
setFieldNames(tempFieldNames);
- const fieldName = tempFieldNames.length === 1 ? tempFieldNames[0].value : undefined;
+ const defaultSelectedField = inferrer.getInputField();
+
+ const fieldName =
+ defaultSelectedField &&
+ tempFieldNames.find((field) => field.value === defaultSelectedField)
+ ? defaultSelectedField
+ : tempFieldNames[0].value;
+ // Only set a field if it's the default field
+ // if (inferrer.getInputField() === DEFAULT_INPUT_FIELD) {
inferrer.setInputField(fieldName);
+ // }
}
},
- [selectedDataView, inferrer]
+ [selectedDataView, inferrer] // defaultSelectedField
);
useEffect(
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts
index 8dc0bf6b88815..bdd082cf8ca04 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts
@@ -31,7 +31,7 @@ export type InferenceOptions =
| estypes.MlTextEmbeddingInferenceOptions
| estypes.MlQuestionAnsweringInferenceUpdateOptions;
-const DEFAULT_INPUT_FIELD = 'text_field';
+export const DEFAULT_INPUT_FIELD = 'text_field';
export const DEFAULT_INFERENCE_TIME_OUT = '30s';
export type FormattedNerResponse = Array<{
@@ -72,8 +72,10 @@ export abstract class InferenceBase {
private isValid$ = new BehaviorSubject(false);
private pipeline$ = new BehaviorSubject({});
private supportedFieldTypes: ES_FIELD_TYPES[] = [ES_FIELD_TYPES.TEXT];
+ private selectedDataViewId: string | undefined;
protected readonly info: string[] = [];
+ public switchToCreationMode?: () => void;
private subscriptions$: Subscription = new Subscription();
@@ -87,8 +89,13 @@ export abstract class InferenceBase {
this.inputField$.next(this.modelInputField);
}
+ public setSwitchtoCreationMode(callback: () => void) {
+ this.switchToCreationMode = callback;
+ }
+
public destroy() {
this.subscriptions$.unsubscribe();
+ this.pipeline$.unsubscribe();
}
protected initialize(
@@ -162,6 +169,15 @@ export abstract class InferenceBase {
this.runningState$.next(RUNNING_STATE.STOPPED);
}
+ public setSelectedDataViewId(dataViewId: string) {
+ // Data view selected for testing
+ this.selectedDataViewId = dataViewId;
+ }
+
+ public getSelectedDataViewId() {
+ return this.selectedDataViewId;
+ }
+
public setInputField(field: string | undefined) {
// if the field is not set, change to be the same as the model input field
this.inputField$.next(field === undefined ? this.modelInputField : field);
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/index_input.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/index_input.tsx
index 4dbe900283657..4b87ddccfb4b2 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/index_input.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/index_input.tsx
@@ -11,7 +11,6 @@ import useObservable from 'react-use/lib/useObservable';
import {
EuiSpacer,
- EuiButton,
EuiButtonEmpty,
EuiFlexGroup,
EuiFlexItem,
@@ -28,13 +27,22 @@ import { ErrorMessage } from '../../inference_error';
import type { InferrerType } from '..';
import { useIndexInput, InferenceInputFormIndexControls } from '../index_input';
import { RUNNING_STATE } from '../inference_base';
+import { InputFormControls } from './input_form_controls';
+import { useTestTrainedModelsContext } from '../../test_trained_models_context';
interface Props {
inferrer: InferrerType;
}
export const IndexInputForm: FC = ({ inferrer }) => {
- const data = useIndexInput({ inferrer });
+ const {
+ currentContext: { defaultSelectedDataViewId, createPipelineFlyoutOpen },
+ } = useTestTrainedModelsContext();
+
+ const data = useIndexInput({
+ inferrer,
+ defaultSelectedDataViewId,
+ });
const { reloadExamples, selectedField } = data;
const [errorText, setErrorText] = useState(null);
@@ -60,23 +68,26 @@ export const IndexInputForm: FC = ({ inferrer }) => {
return (
<>{infoComponent}>
-
+
-
-
+
-
+
{runningState === RUNNING_STATE.RUNNING ? : null}
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/input_form_controls.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/input_form_controls.tsx
new file mode 100644
index 0000000000000..18cacbb745504
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/input_form_controls.tsx
@@ -0,0 +1,63 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { FC } from 'react';
+
+import { EuiButton, EuiButtonEmpty, EuiFlexItem } from '@elastic/eui';
+
+import { FormattedMessage } from '@kbn/i18n-react';
+import type { InferrerType } from '..';
+
+interface Props {
+ testButtonDisabled: boolean;
+ createPipelineButtonDisabled: boolean;
+ inferrer: InferrerType;
+ showCreatePipelineButton?: boolean;
+}
+
+export const InputFormControls: FC = ({
+ testButtonDisabled,
+ createPipelineButtonDisabled,
+ inferrer,
+ showCreatePipelineButton,
+}) => {
+ return (
+ <>
+
+
+
+
+
+ {showCreatePipelineButton ? (
+
+ {
+ if (inferrer.switchToCreationMode) {
+ inferrer.switchToCreationMode();
+ }
+ }}
+ >
+
+
+
+ ) : null}
+ >
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/text_input.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/text_input.tsx
index fc162a305c32b..ae5a4c72cac60 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/text_input.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_input_form/text_input.tsx
@@ -8,7 +8,7 @@
import React, { FC, useState, useMemo, useCallback, FormEventHandler } from 'react';
import useObservable from 'react-use/lib/useObservable';
-import { EuiSpacer, EuiButton, EuiTabs, EuiTab, EuiForm } from '@elastic/eui';
+import { EuiFlexGroup, EuiSpacer, EuiTabs, EuiTab, EuiForm } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { extractErrorMessage } from '@kbn/ml-error-utils';
@@ -18,6 +18,7 @@ import type { InferrerType } from '..';
import { OutputLoadingContent } from '../../output_loading';
import { RUNNING_STATE } from '../inference_base';
import { RawOutput } from '../raw_output';
+import { InputFormControls } from './input_form_controls';
interface Props {
inferrer: InferrerType;
@@ -57,17 +58,15 @@ export const TextInputForm: FC = ({ inferrer }) => {
<>{inputComponent}>
-
-
+
-
+
{runningState !== RUNNING_STATE.STOPPED ? (
<>
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx
index 4747d9c149186..80ee311d533a8 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx
@@ -7,6 +7,7 @@
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import React, { FC, useMemo, useEffect } from 'react';
+import { cloneDeep } from 'lodash';
import { TRAINED_MODEL_TYPE, SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils';
import { NerInference } from './models/ner';
@@ -22,52 +23,182 @@ import {
import { TextEmbeddingInference } from './models/text_embedding';
import { useMlApiContext } from '../../contexts/kibana';
+import { type TestTrainedModelsContextType } from './test_trained_models_context';
import { InferenceInputForm } from './models/inference_input_form';
import { InferrerType } from './models';
import { INPUT_TYPE } from './models/inference_base';
import { TextExpansionInference } from './models/text_expansion';
+import { type InferecePipelineCreationState } from '../create_pipeline_for_model/state';
+import {
+ getInferencePropertiesFromPipelineConfig,
+ isMlIngestInferenceProcessor,
+ isMlInferencePipelineInferenceConfig,
+} from '../create_pipeline_for_model/get_inference_properties_from_pipeline_config';
interface Props {
model: estypes.MlTrainedModelConfig;
inputType: INPUT_TYPE;
deploymentId: string;
+ handlePipelineConfigUpdate?: (configUpdate: Partial) => void;
+ externalPipelineConfig?: estypes.IngestPipeline;
+ setCurrentContext?: React.Dispatch;
}
-export const SelectedModel: FC = ({ model, inputType, deploymentId }) => {
+export const SelectedModel: FC = ({
+ model,
+ inputType,
+ deploymentId,
+ handlePipelineConfigUpdate,
+ externalPipelineConfig,
+ setCurrentContext,
+}) => {
const { trainedModels } = useMlApiContext();
const inferrer = useMemo(() => {
- if (model.model_type === TRAINED_MODEL_TYPE.PYTORCH) {
- const taskType = Object.keys(model.inference_config ?? {})[0];
+ const taskType = Object.keys(model.inference_config ?? {})[0];
+ let tempInferrer: InferrerType | undefined;
+ const pipelineConfigValues = externalPipelineConfig
+ ? getInferencePropertiesFromPipelineConfig(taskType, externalPipelineConfig)
+ : null;
+ if (model.model_type === TRAINED_MODEL_TYPE.PYTORCH) {
switch (taskType) {
case SUPPORTED_PYTORCH_TASKS.NER:
- return new NerInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new NerInference(trainedModels, model, inputType, deploymentId);
+ break;
case SUPPORTED_PYTORCH_TASKS.TEXT_CLASSIFICATION:
- return new TextClassificationInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new TextClassificationInference(
+ trainedModels,
+ model,
+ inputType,
+ deploymentId
+ );
+ break;
case SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION:
- return new ZeroShotClassificationInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new ZeroShotClassificationInference(
+ trainedModels,
+ model,
+ inputType,
+ deploymentId
+ );
+ if (pipelineConfigValues) {
+ const { labels, multi_label: multiLabel } = pipelineConfigValues;
+ if (labels && multiLabel !== undefined) {
+ tempInferrer.setLabelsText(Array.isArray(labels) ? labels.join(',') : labels);
+ tempInferrer.setMultiLabel(Boolean(multiLabel));
+ }
+ }
+ break;
case SUPPORTED_PYTORCH_TASKS.TEXT_EMBEDDING:
- return new TextEmbeddingInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new TextEmbeddingInference(trainedModels, model, inputType, deploymentId);
+ break;
case SUPPORTED_PYTORCH_TASKS.FILL_MASK:
- return new FillMaskInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new FillMaskInference(trainedModels, model, inputType, deploymentId);
+ break;
case SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING:
- return new QuestionAnsweringInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new QuestionAnsweringInference(
+ trainedModels,
+ model,
+ inputType,
+ deploymentId
+ );
+ if (pipelineConfigValues?.question) {
+ tempInferrer.setQuestionText(pipelineConfigValues.question);
+ }
+ break;
case SUPPORTED_PYTORCH_TASKS.TEXT_EXPANSION:
- return new TextExpansionInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new TextExpansionInference(trainedModels, model, inputType, deploymentId);
+ break;
default:
break;
}
} else if (model.model_type === TRAINED_MODEL_TYPE.LANG_IDENT) {
- return new LangIdentInference(trainedModels, model, inputType, deploymentId);
+ tempInferrer = new LangIdentInference(trainedModels, model, inputType, deploymentId);
+ }
+ if (tempInferrer) {
+ if (pipelineConfigValues) {
+ tempInferrer.setInputField(pipelineConfigValues.inputField);
+ }
+ if (externalPipelineConfig === undefined) {
+ tempInferrer.setSwitchtoCreationMode(() => {
+ if (tempInferrer && setCurrentContext) {
+ setCurrentContext({
+ pipelineConfig: tempInferrer.getPipeline(),
+ defaultSelectedDataViewId: tempInferrer.getSelectedDataViewId(),
+ createPipelineFlyoutOpen: true,
+ });
+ }
+ });
+ } else {
+ tempInferrer?.getPipeline$().subscribe((testPipeline) => {
+ if (handlePipelineConfigUpdate && testPipeline && externalPipelineConfig) {
+ const {
+ fieldMap: testFieldMap,
+ inferenceConfig: testInferenceConfig,
+ labels,
+ multi_label: multiLabel,
+ question,
+ } = getInferencePropertiesFromPipelineConfig(taskType, testPipeline);
+
+ const updatedPipeline = cloneDeep(externalPipelineConfig);
+ const { inferenceObj: externalInference, inferenceConfig: externalInferenceConfig } =
+ getInferencePropertiesFromPipelineConfig(taskType, updatedPipeline);
+
+ if (externalInference) {
+ // Always update target field change
+ externalInference.field_map = testFieldMap;
+
+ if (externalInferenceConfig === undefined) {
+ externalInference.inference_config = testInferenceConfig;
+ } else if (
+ isMlIngestInferenceProcessor(externalInference) &&
+ isMlInferencePipelineInferenceConfig(externalInference.inference_config)
+ ) {
+ // Only update the properties that change in the test step to avoid overwriting user edits
+ if (
+ taskType === SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION &&
+ labels &&
+ multiLabel !== undefined
+ ) {
+ const external =
+ externalInference.inference_config[
+ SUPPORTED_PYTORCH_TASKS.ZERO_SHOT_CLASSIFICATION
+ ];
+
+ if (external) {
+ external.multi_label = multiLabel;
+ external.labels = labels;
+ }
+ } else if (
+ taskType === SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING &&
+ question !== undefined
+ ) {
+ const external =
+ externalInference.inference_config[SUPPORTED_PYTORCH_TASKS.QUESTION_ANSWERING];
+
+ if (external) {
+ external.question = question;
+ }
+ }
+ }
+ }
+
+ handlePipelineConfigUpdate({
+ initialPipelineConfig: updatedPipeline,
+ });
+ }
+ });
+ }
}
- }, [inputType, model, trainedModels, deploymentId]);
+ return tempInferrer;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [inputType, model, trainedModels, deploymentId, setCurrentContext]);
useEffect(() => {
return () => {
inferrer?.destroy();
};
- }, [inferrer]);
+ }, [inferrer, model.model_id]);
if (inferrer !== undefined) {
return ;
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/test_flyout.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/test_flyout.tsx
index 434621d11773b..f595fd1de35d7 100644
--- a/x-pack/plugins/ml/public/application/model_management/test_models/test_flyout.tsx
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/test_flyout.tsx
@@ -5,126 +5,36 @@
* 2.0.
*/
-import React, { FC, useState, useMemo } from 'react';
+import React, { FC } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
-import {
- EuiFlyout,
- EuiFlyoutBody,
- EuiFlyoutHeader,
- EuiFormRow,
- EuiSelect,
- EuiSpacer,
- EuiTab,
- EuiTabs,
- EuiTitle,
- useEuiPaddingSize,
-} from '@elastic/eui';
+import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiSpacer, EuiTitle } from '@elastic/eui';
-import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils';
-import { SelectedModel } from './selected_model';
-import { INPUT_TYPE } from './models/inference_base';
import { type ModelItem } from '../models_list';
+import { TestTrainedModelContent } from './test_trained_model_content';
interface Props {
model: ModelItem;
onClose: () => void;
}
-export const TestTrainedModelFlyout: FC = ({ model, onClose }) => {
- const [deploymentId, setDeploymentId] = useState(model.deployment_ids[0]);
- const mediumPadding = useEuiPaddingSize('m');
-
- const [inputType, setInputType] = useState(INPUT_TYPE.TEXT);
-
- const onlyShowTab: INPUT_TYPE | undefined = useMemo(() => {
- return (model.type ?? []).includes(SUPPORTED_PYTORCH_TASKS.TEXT_EXPANSION)
- ? INPUT_TYPE.INDEX
- : undefined;
- }, [model]);
-
- return (
- <>
-
-
-
-
-
-
-
-
-
- {model.model_id}
-
-
-
- {model.deployment_ids.length > 1 ? (
- <>
-
- }
- >
- {
- return { text: v, value: v };
- })}
- value={deploymentId}
- onChange={(e) => {
- setDeploymentId(e.target.value);
- }}
- />
-
-
- >
- ) : null}
-
- {onlyShowTab === undefined ? (
- <>
-
- setInputType(INPUT_TYPE.TEXT)}
- >
-
-
- setInputType(INPUT_TYPE.INDEX)}
- >
-
-
-
-
-
- >
- ) : null}
-
- = ({ model, onClose }) => (
+
+
+
+
+
-
-
- >
- );
-};
+
+
+
+
+ {model.model_id}
+
+
+
+
+
+
+);
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/test_model_and_pipeline_creation_flyout.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/test_model_and_pipeline_creation_flyout.tsx
new file mode 100644
index 0000000000000..33c4e69df59b6
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/test_model_and_pipeline_creation_flyout.tsx
@@ -0,0 +1,37 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { FC, useState } from 'react';
+
+import {
+ type TestTrainedModelsContextType,
+ TestTrainedModelsContext,
+} from './test_trained_models_context';
+import type { ModelItem } from '../models_list';
+import { TestTrainedModelFlyout } from './test_flyout';
+import { CreatePipelineForModelFlyout } from '../create_pipeline_for_model/create_pipeline_for_model_flyout';
+
+interface Props {
+ model: ModelItem;
+ onClose: (refreshList?: boolean) => void;
+}
+export const TestModelAndPipelineCreationFlyout: FC = ({ model, onClose }) => {
+ const [currentContext, setCurrentContext] = useState({
+ pipelineConfig: undefined,
+ createPipelineFlyoutOpen: false,
+ });
+
+ return (
+
+ {currentContext.createPipelineFlyoutOpen === false ? (
+
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_model_content.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_model_content.tsx
new file mode 100644
index 0000000000000..52665343cb351
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_model_content.tsx
@@ -0,0 +1,115 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor 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, { FC, useState, useMemo } from 'react';
+
+import { SUPPORTED_PYTORCH_TASKS } from '@kbn/ml-trained-models-utils';
+import { FormattedMessage } from '@kbn/i18n-react';
+import { EuiFormRow, EuiSelect, EuiSpacer, EuiTab, EuiTabs, useEuiPaddingSize } from '@elastic/eui';
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { SelectedModel } from './selected_model';
+import { type ModelItem } from '../models_list';
+import { INPUT_TYPE } from './models/inference_base';
+import { useTestTrainedModelsContext } from './test_trained_models_context';
+import { type InferecePipelineCreationState } from '../create_pipeline_for_model/state';
+
+interface ContentProps {
+ model: ModelItem;
+ handlePipelineConfigUpdate?: (configUpdate: Partial) => void;
+ externalPipelineConfig?: estypes.IngestPipeline;
+}
+
+export const TestTrainedModelContent: FC = ({
+ model,
+ handlePipelineConfigUpdate,
+ externalPipelineConfig,
+}) => {
+ const [deploymentId, setDeploymentId] = useState(model.deployment_ids[0]);
+ const mediumPadding = useEuiPaddingSize('m');
+
+ const [inputType, setInputType] = useState(INPUT_TYPE.TEXT);
+ const {
+ currentContext: { createPipelineFlyoutOpen },
+ setCurrentContext,
+ } = useTestTrainedModelsContext();
+
+ const onlyShowTab: INPUT_TYPE | undefined = useMemo(() => {
+ return (model.type ?? []).includes(SUPPORTED_PYTORCH_TASKS.TEXT_EXPANSION) ||
+ createPipelineFlyoutOpen
+ ? INPUT_TYPE.INDEX
+ : undefined;
+ }, [model, createPipelineFlyoutOpen]);
+ return (
+ <>
+ {' '}
+ {model.deployment_ids.length > 1 ? (
+ <>
+
+ }
+ >
+ {
+ return { text: v, value: v };
+ })}
+ value={deploymentId}
+ onChange={(e) => {
+ setDeploymentId(e.target.value);
+ }}
+ />
+
+
+ >
+ ) : null}
+ {onlyShowTab === undefined ? (
+ <>
+
+ setInputType(INPUT_TYPE.TEXT)}
+ >
+
+
+ setInputType(INPUT_TYPE.INDEX)}
+ >
+
+
+
+
+
+ >
+ ) : null}
+
+ >
+ );
+};
diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_models_context.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_models_context.tsx
new file mode 100644
index 0000000000000..5db45a334b16a
--- /dev/null
+++ b/x-pack/plugins/ml/public/application/model_management/test_models/test_trained_models_context.tsx
@@ -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 { createContext, Dispatch, useContext } from 'react';
+import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+
+export interface TestTrainedModelsContextType {
+ pipelineConfig?: estypes.IngestPipeline;
+ createPipelineFlyoutOpen: boolean;
+ defaultSelectedDataViewId?: string;
+}
+export const TestTrainedModelsContext = createContext<
+ | {
+ currentContext: TestTrainedModelsContextType;
+ setCurrentContext: Dispatch;
+ }
+ | undefined
+>(undefined);
+
+export function useTestTrainedModelsContext() {
+ const testTrainedModelsContext = useContext(TestTrainedModelsContext);
+
+ if (testTrainedModelsContext === undefined) {
+ throw new Error('TestTrainedModelsContext has not been initialized.');
+ }
+
+ return testTrainedModelsContext;
+}
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 6acdf51501610..779921068028e 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -26820,7 +26820,6 @@
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.failureMessage": "Impossible de créer le pipeline \"{pipelineName}\".",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.successMessage": "Le pipeline \"{pipelineName}\" a été créé avec succès.",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.createDataViewLabel": "Créer une vue de données",
- "xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.description": "Ce pipeline est créé en respectant la configuration ci-dessous.",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destinationIndexLabel": "Nom de l'index de destination",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexEmpty": "Entrer un nom d'index de destination valide",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexExists": "Un index portant ce nom existe déjà.",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 0ed5b8922a49f..27125a6261b28 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -26820,7 +26820,6 @@
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.failureMessage": "'{pipelineName}'を作成できません。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.successMessage": "'{pipelineName}'は正常に作成されました。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.createDataViewLabel": "データビューを作成",
- "xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.description": "このパイプラインは以下の構成で作成されます。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destinationIndexLabel": "デスティネーションインデックス名",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexEmpty": "有効なデスティネーションインデックス名を入力",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexExists": "この名前のインデックスがすでに存在します。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 2def05af32b75..9f4ab71dc071c 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -26818,7 +26818,6 @@
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.failureMessage": "无法创建“{pipelineName}”。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.create.successMessage": "已成功创建“{pipelineName}”。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.createDataViewLabel": "创建数据视图",
- "xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.description": "将使用以下配置创建此管道。",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destinationIndexLabel": "目标索引名称",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexEmpty": "输入有效的目标索引",
"xpack.ml.trainedModels.content.indices.pipelines.addInferencePipelineModal.steps.review.destIndexExists": "已存在具有此名称的索引。",
From c62790773374a8eeb47c0398c285148004442d60 Mon Sep 17 00:00:00 2001
From: Mykola Harmash
Date: Tue, 19 Dec 2023 16:48:35 +0100
Subject: [PATCH 09/95] [ObsUX] Add UI Setting for controling Profiling
visibility in Infra (#173294)
Closes https://github.com/elastic/kibana/issues/173154
Adds a UI setting to control Infra+Profiling integration from Kibana's
Advanced Settings as well as from the Infra Settings screen.
Note that the plugin config feature flag is still there because I
realized we need it to disable Profiling integration in serverless.
https://github.com/elastic/kibana/assets/793851/2a5ace9d-9e18-49a4-be95-c722f24072a7
### How to test
* Make sure profiling is enabled in `kibana.dev.yml`
```
xpack.profiling.enabled: true
```
* Start kibana in traditional mode, go to Infra Settings
* Make sure there is the new toggle for Profiling integration and it's
on
* Go to one of your host's details and make sure you see the profiling
tab
* Toggle the Profiling integration setting off and check that the tap in
host details is not visible
* Start kibana in serverless mode
* Make sure there is no new setting neither in Infra Settings nor in
Advanced Settings
* Make sure Profiling tab is not visible in host details
---------
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
docs/management/advanced-options.asciidoc | 3 ++
.../server/collectors/management/schema.ts | 4 +++
.../server/collectors/management/types.ts | 1 +
src/plugins/telemetry/schema/oss_plugins.json | 6 ++++
.../asset_details/hooks/use_page_header.tsx | 19 +++++++-----
.../overview/kpis/cpu_profiling_prompt.tsx | 13 ++++++---
.../use_profiling_integration_setting.ts | 21 ++++++++++++++
.../settings/features_configuration_panel.tsx | 18 +++++++++++-
.../source_configuration_settings.tsx | 10 +++++--
x-pack/plugins/observability/common/index.ts | 1 +
.../observability/common/ui_settings_keys.ts | 2 ++
.../observability/server/ui_settings.ts | 25 ++++++++++++++--
.../functional/apps/infra/node_details.ts | 29 +++++++++++++++++++
.../functional/page_objects/asset_details.ts | 16 ++++++++++
14 files changed, 150 insertions(+), 18 deletions(-)
create mode 100644 x-pack/plugins/infra/public/hooks/use_profiling_integration_setting.ts
diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc
index 03a85d319cf55..c0307253a7208 100644
--- a/docs/management/advanced-options.asciidoc
+++ b/docs/management/advanced-options.asciidoc
@@ -451,6 +451,9 @@ preview:[] When enabled, allows users to create Service Groups from the APM Serv
[[observability-apm-trace-explorer-tab]]`observability:apmTraceExplorerTab`::
preview:[] Enable the APM Trace Explorer feature, that allows you to search and inspect traces with KQL or EQL.
+[[observability-infrastructure-profiling-integration]]`observability:enableInfrastructureProfilingIntegration`::
+preview:[] Enables the Profiling view in Host details within Infrastructure.
+
[float]
[[kibana-reporting-settings]]
==== Reporting
diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts
index 537b7739bcc0d..1fa2407cdd287 100644
--- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts
+++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts
@@ -581,6 +581,10 @@ export const stackManagementSchema: MakeSchemaFrom = {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
},
+ 'observability:enableInfrastructureProfilingIntegration': {
+ type: 'boolean',
+ _meta: { description: 'Non-default value of setting.' },
+ },
'securitySolution:enableGroupedNav': {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts
index 273864af2bb4a..33518b5389f57 100644
--- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts
+++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts
@@ -46,6 +46,7 @@ export interface UsageStats {
'observability:apmAWSLambdaPriceFactor': string;
'observability:apmAWSLambdaRequestCostPerMillion': number;
'observability:enableInfrastructureHostsView': boolean;
+ 'observability:enableInfrastructureProfilingIntegration': boolean;
'observability:apmAgentExplorerView': boolean;
'visualization:heatmap:maxBuckets': number;
'visualization:colorMapping': string;
diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json
index 8c2a7b13d52ca..ec17c9b9d1a3b 100644
--- a/src/plugins/telemetry/schema/oss_plugins.json
+++ b/src/plugins/telemetry/schema/oss_plugins.json
@@ -10061,6 +10061,12 @@
"description": "Non-default value of setting."
}
},
+ "observability:enableInfrastructureProfilingIntegration": {
+ "type": "boolean",
+ "_meta": {
+ "description": "Non-default value of setting."
+ }
+ },
"securitySolution:enableGroupedNav": {
"type": "boolean",
"_meta": {
diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx
index 3fae1eca66a40..905def3ab0bc0 100644
--- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx
@@ -5,22 +5,23 @@
* 2.0.
*/
import {
- EuiIcon,
- type EuiPageHeaderProps,
- type EuiBreadcrumbsProps,
EuiFlexGroup,
EuiFlexItem,
+ EuiIcon,
+ type EuiBreadcrumbsProps,
+ type EuiPageHeaderProps,
} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n-react';
import { useLinkProps } from '@kbn/observability-shared-plugin/public';
-import React, { useCallback, useMemo } from 'react';
import { capitalize } from 'lodash';
+import React, { useCallback, useMemo } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
-import { FormattedMessage } from '@kbn/i18n-react';
import { usePluginConfig } from '../../../containers/plugin_config_context';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
+import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting';
import { APM_HOST_FILTER_FIELD } from '../constants';
import { LinkToAlertsRule, LinkToApmServices, LinkToNodeDetails } from '../links';
-import { ContentTabIds, type RouteState, type LinkOptions, type Tab, type TabIds } from '../types';
+import { ContentTabIds, type LinkOptions, type RouteState, type Tab, type TabIds } from '../types';
import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props';
import { useTabSwitcherContext } from './use_tab_switcher';
@@ -110,12 +111,14 @@ const useRightSideItems = (links?: LinkOptions[]) => {
const useFeatureFlagTabs = () => {
const { featureFlags } = usePluginConfig();
+ const isProfilingEnabled = useProfilingIntegrationSetting();
+
const featureFlagControlledTabs: Partial> = useMemo(
() => ({
[ContentTabIds.OSQUERY]: featureFlags.osqueryEnabled,
- [ContentTabIds.PROFILING]: featureFlags.profilingEnabled,
+ [ContentTabIds.PROFILING]: isProfilingEnabled,
}),
- [featureFlags.osqueryEnabled, featureFlags.profilingEnabled]
+ [featureFlags.osqueryEnabled, isProfilingEnabled]
);
const isTabEnabled = useCallback(
diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx
index afe39963e966d..291b255e7ce33 100644
--- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx
+++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/cpu_profiling_prompt.tsx
@@ -10,19 +10,24 @@ import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty } from '@elastic/eui';
import { EuiBadge } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
-import { usePluginConfig } from '../../../../../containers/plugin_config_context';
+import { useProfilingIntegrationSetting } from '../../../../../hooks/use_profiling_integration_setting';
import { useTabSwitcherContext } from '../../../hooks/use_tab_switcher';
export function CpuProfilingPrompt() {
const { showTab } = useTabSwitcherContext();
- const { featureFlags } = usePluginConfig();
+ const isProfilingEnabled = useProfilingIntegrationSetting();
- if (!featureFlags.profilingEnabled) {
+ if (!isProfilingEnabled) {
return null;
}
return (
-
+
{i18n.translate('xpack.infra.cpuProfilingPrompt.newBadgeLabel', {
defaultMessage: 'NEW',
diff --git a/x-pack/plugins/infra/public/hooks/use_profiling_integration_setting.ts b/x-pack/plugins/infra/public/hooks/use_profiling_integration_setting.ts
new file mode 100644
index 0000000000000..ee9101af55fc2
--- /dev/null
+++ b/x-pack/plugins/infra/public/hooks/use_profiling_integration_setting.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { useUiSetting } from '@kbn/kibana-react-plugin/public';
+import { enableInfrastructureProfilingIntegration } from '@kbn/observability-plugin/common';
+import { usePluginConfig } from '../containers/plugin_config_context';
+
+export function useProfilingIntegrationSetting(): boolean {
+ const {
+ featureFlags: { profilingEnabled },
+ } = usePluginConfig();
+ const isProfilingUiSettingEnabled = useUiSetting(
+ enableInfrastructureProfilingIntegration
+ );
+
+ return profilingEnabled && isProfilingUiSettingEnabled;
+}
diff --git a/x-pack/plugins/infra/public/pages/metrics/settings/features_configuration_panel.tsx b/x-pack/plugins/infra/public/pages/metrics/settings/features_configuration_panel.tsx
index 19d7392fb7ca1..aa69ef543c68f 100644
--- a/x-pack/plugins/infra/public/pages/metrics/settings/features_configuration_panel.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/settings/features_configuration_panel.tsx
@@ -10,9 +10,13 @@ import { EuiSpacer } from '@elastic/eui';
import { EuiForm } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import React from 'react';
-import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common';
+import {
+ enableInfrastructureHostsView,
+ enableInfrastructureProfilingIntegration,
+} from '@kbn/observability-plugin/common';
import { useEditableSettings } from '@kbn/observability-shared-plugin/public';
import { LazyField } from '@kbn/advanced-settings-plugin/public';
+import { usePluginConfig } from '../../../containers/plugin_config_context';
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana';
type Props = Pick<
@@ -31,6 +35,7 @@ export function FeaturesConfigurationPanel({
const {
services: { docLinks, notifications },
} = useKibanaContextForPlugin();
+ const { featureFlags } = usePluginConfig();
return (
@@ -52,6 +57,17 @@ export function FeaturesConfigurationPanel({
toasts={notifications.toasts}
unsavedChanges={unsavedChanges[enableInfrastructureHostsView]}
/>
+ {featureFlags.profilingEnabled && (
+
+ )}
);
}
diff --git a/x-pack/plugins/infra/public/pages/metrics/settings/source_configuration_settings.tsx b/x-pack/plugins/infra/public/pages/metrics/settings/source_configuration_settings.tsx
index 5769f861234c4..a064aaf0e151f 100644
--- a/x-pack/plugins/infra/public/pages/metrics/settings/source_configuration_settings.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/settings/source_configuration_settings.tsx
@@ -17,7 +17,10 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import React, { useCallback } from 'react';
import { Prompt, useEditableSettings } from '@kbn/observability-shared-plugin/public';
-import { enableInfrastructureHostsView } from '@kbn/observability-plugin/common';
+import {
+ enableInfrastructureHostsView,
+ enableInfrastructureProfilingIntegration,
+} from '@kbn/observability-plugin/common';
import { SourceLoadingPage } from '../../../components/source_loading_page';
import { useSourceContext } from '../../../containers/metrics_source';
import { useInfraMLCapabilitiesContext } from '../../../containers/ml/infra_ml_capabilities';
@@ -61,7 +64,10 @@ export const SourceConfigurationSettings = ({
formState,
formStateChanges,
} = useSourceConfigurationFormState(source && source.configuration);
- const infraUiSettings = useEditableSettings('infra_metrics', [enableInfrastructureHostsView]);
+ const infraUiSettings = useEditableSettings('infra_metrics', [
+ enableInfrastructureHostsView,
+ enableInfrastructureProfilingIntegration,
+ ]);
const resetAllUnsavedChanges = useCallback(() => {
resetForm();
diff --git a/x-pack/plugins/observability/common/index.ts b/x-pack/plugins/observability/common/index.ts
index 3a86e264095bd..143bf77a1b0cc 100644
--- a/x-pack/plugins/observability/common/index.ts
+++ b/x-pack/plugins/observability/common/index.ts
@@ -32,6 +32,7 @@ export {
apmTraceExplorerTab,
apmLabsButton,
enableInfrastructureHostsView,
+ enableInfrastructureProfilingIntegration,
enableAwsLambdaMetrics,
enableAgentExplorerView,
apmAWSLambdaPriceFactor,
diff --git a/x-pack/plugins/observability/common/ui_settings_keys.ts b/x-pack/plugins/observability/common/ui_settings_keys.ts
index 5745882055cab..bcc2f0451caac 100644
--- a/x-pack/plugins/observability/common/ui_settings_keys.ts
+++ b/x-pack/plugins/observability/common/ui_settings_keys.ts
@@ -17,6 +17,8 @@ export const apmServiceGroupMaxNumberOfServices =
export const apmTraceExplorerTab = 'observability:apmTraceExplorerTab';
export const apmLabsButton = 'observability:apmLabsButton';
export const enableInfrastructureHostsView = 'observability:enableInfrastructureHostsView';
+export const enableInfrastructureProfilingIntegration =
+ 'observability:enableInfrastructureProfilingIntegration';
export const enableAwsLambdaMetrics = 'observability:enableAwsLambdaMetrics';
export const enableAgentExplorerView = 'observability:apmAgentExplorerView';
export const apmAWSLambdaPriceFactor = 'observability:apmAWSLambdaPriceFactor';
diff --git a/x-pack/plugins/observability/server/ui_settings.ts b/x-pack/plugins/observability/server/ui_settings.ts
index 98260fff5f4c7..8029b412ebb6a 100644
--- a/x-pack/plugins/observability/server/ui_settings.ts
+++ b/x-pack/plugins/observability/server/ui_settings.ts
@@ -37,6 +37,7 @@ import {
profilingPervCPUWattArm64,
profilingAWSCostDiscountRate,
profilingCostPervCPUPerHour,
+ enableInfrastructureProfilingIntegration,
} from '../common/ui_settings_keys';
const betaLabel = i18n.translate('xpack.observability.uiSettings.betaLabel', {
@@ -236,6 +237,24 @@ export const uiSettings: Record = {
}),
schema: schema.boolean(),
},
+ [enableInfrastructureProfilingIntegration]: {
+ category: [observabilityFeatureId],
+ name: i18n.translate('xpack.observability.enableInfrastructureProfilingIntegration', {
+ defaultMessage: 'Universal Profiling integration in Infrastructure',
+ }),
+ value: true,
+ description: i18n.translate(
+ 'xpack.observability.enableInfrastructureProfilingIntegrationDescription',
+ {
+ defaultMessage:
+ '{betaLabel} Enable Universal Profiling integration in the Infrastructure app.',
+ values: {
+ betaLabel: `[${betaLabel}]`,
+ },
+ }
+ ),
+ schema: schema.boolean(),
+ },
[enableAwsLambdaMetrics]: {
category: [observabilityFeatureId],
name: i18n.translate('xpack.observability.enableAwsLambdaMetrics', {
@@ -415,9 +434,9 @@ export const uiSettings: Record = {
}),
value: 1.7,
description: i18n.translate('xpack.observability.profilingDatacenterPUEUiSettingDescription', {
- defaultMessage: `Data center power usage effectiveness (PUE) measures how efficiently a data center uses energy. Defaults to 1.7, the average on-premise data center PUE according to the {uptimeLink} survey
+ defaultMessage: `Data center power usage effectiveness (PUE) measures how efficiently a data center uses energy. Defaults to 1.7, the average on-premise data center PUE according to the {uptimeLink} survey
- You can also use the PUE that corresponds with your cloud provider:
+ You can also use the PUE that corresponds with your cloud provider:
- AWS: 1.135
- GCP: 1.1
@@ -444,7 +463,7 @@ export const uiSettings: Record = {
}),
value: 0.000379069,
description: i18n.translate('xpack.observability.profilingCo2PerKWHUiSettingDescription', {
- defaultMessage: `Carbon intensity measures how clean your data center electricity is.
+ defaultMessage: `Carbon intensity measures how clean your data center electricity is.
Specifically, it measures the average amount of CO2 emitted per kilowatt-hour (kWh) of electricity consumed in a particular region.
Use the cloud carbon footprint {datasheetLink} to update this value according to your region. Defaults to US East (N. Virginia).`,
values: {
diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts
index e4cfdaae3d227..c4bbbbfc2d09c 100644
--- a/x-pack/test/functional/apps/infra/node_details.ts
+++ b/x-pack/test/functional/apps/infra/node_details.ts
@@ -7,6 +7,7 @@
import moment from 'moment';
import expect from '@kbn/expect';
+import { enableInfrastructureProfilingIntegration } from '@kbn/observability-plugin/common';
import { FtrProviderContext } from '../../ftr_provider_context';
import { DATES, NODE_DETAILS_PATH, DATE_PICKER_FORMAT } from './constants';
@@ -67,6 +68,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await browser.refresh();
};
+ const setInfrastructureProfilingIntegrationUiSetting = async (value: boolean = true) => {
+ await kibanaServer.uiSettings.update({ [enableInfrastructureProfilingIntegration]: value });
+ await browser.refresh();
+ await pageObjects.header.waitUntilLoadingHasFinished();
+ };
+
describe('Node Details', () => {
describe('#With Asset Details', () => {
before(async () => {
@@ -190,6 +197,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.header.waitUntilLoadingHasFinished();
await pageObjects.assetDetails.overviewAlertsTitleExists();
});
+
+ it('shows the CPU Profiling prompt if UI setting for Profiling integration is enabled', async () => {
+ await setInfrastructureProfilingIntegrationUiSetting(true);
+ await pageObjects.assetDetails.cpuProfilingPromptExists();
+ });
+
+ it('hides the CPU Profiling prompt if UI setting for Profiling integration is disabled', async () => {
+ await setInfrastructureProfilingIntegrationUiSetting(false);
+ await pageObjects.assetDetails.cpuProfilingPromptMissing();
+ });
});
describe('Metadata Tab', () => {
@@ -312,6 +329,18 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
+ describe('Profiling tab', () => {
+ it('shows the Profiling tab if Profiling integration UI setting is enabled', async () => {
+ await setInfrastructureProfilingIntegrationUiSetting(true);
+ await pageObjects.assetDetails.profilingTabExists();
+ });
+
+ it('hides the Profiling tab if Profiling integration UI setting is disabled', async () => {
+ await setInfrastructureProfilingIntegrationUiSetting(false);
+ await pageObjects.assetDetails.profilingTabMissing();
+ });
+ });
+
describe('Host with alerts and no processes', () => {
before(async () => {
await navigateToNodeDetails('demo-stack-mysql-01', 'demo-stack-mysql-01');
diff --git a/x-pack/test/functional/page_objects/asset_details.ts b/x-pack/test/functional/page_objects/asset_details.ts
index ef4e8967e6922..00274c6af565e 100644
--- a/x-pack/test/functional/page_objects/asset_details.ts
+++ b/x-pack/test/functional/page_objects/asset_details.ts
@@ -62,6 +62,22 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
return testSubjects.click('infraAssetDetailsMetadataShowAllButton');
},
+ async cpuProfilingPromptExists() {
+ return await testSubjects.existOrFail('infraAssetDetailsCPUProfilingPrompt');
+ },
+
+ async cpuProfilingPromptMissing() {
+ return await testSubjects.missingOrFail('infraAssetDetailsCPUProfilingPrompt');
+ },
+
+ async profilingTabExists() {
+ return await testSubjects.existOrFail('infraAssetDetailsProfilingTab');
+ },
+
+ async profilingTabMissing() {
+ return await testSubjects.missingOrFail('infraAssetDetailsProfilingTab');
+ },
+
// Metadata
async clickMetadataTab() {
return testSubjects.click('infraAssetDetailsMetadataTab');
From 15ca37fccc45ffdd67313a29b960a67cfc210cdc Mon Sep 17 00:00:00 2001
From: Philippe Oberti
Date: Tue, 19 Dec 2023 09:56:17 -0600
Subject: [PATCH 10/95] [Security Solution][Timeline] cleanup removing the
unnecessary timeline folder under timelines/store (#172414)
---
.../cell_action/add_to_timeline.test.ts | 2 +-
.../cell_action/add_to_timeline.ts | 2 +-
.../investigate_in_new_timeline.test.ts | 4 +--
.../investigate_in_new_timeline.ts | 6 ++--
.../discover/add_to_timeline.test.ts | 2 +-
.../lens/add_to_timeline.test.ts | 2 +-
.../add_to_timeline/lens/add_to_timeline.ts | 2 +-
.../actions/filter/cell_action/filter_in.ts | 2 +-
.../actions/filter/cell_action/filter_out.ts | 2 +-
.../actions/filter/lens/create_action.ts | 2 +-
.../cell_action/toggle_column.ts | 4 +--
.../public/app/home/global_header/index.tsx | 4 +--
.../public/app/home/index.test.tsx | 6 ++--
.../assistant/comment_actions/index.tsx | 2 +-
.../assistant/send_to_timeline/index.tsx | 2 +-
.../components/use_insert_timeline/index.tsx | 4 +--
.../public/cases/pages/index.tsx | 2 +-
.../control_columns/row_action/index.tsx | 2 +-
.../use_discover_in_timeline_actions.test.tsx | 2 +-
.../use_discover_in_timeline_actions.tsx | 4 +--
.../drag_drop_context_wrapper.tsx | 4 +--
.../components/endpoint/route_capture.tsx | 2 +-
.../event_details/event_fields_browser.tsx | 4 +--
.../event_details/overview/index.tsx | 2 +-
.../table/investigate_in_timeline_button.tsx | 2 +-
.../guided_onboarding_tour/tour_step.tsx | 4 +--
.../components/header_actions/actions.tsx | 6 ++--
.../header_actions/header_actions.test.tsx | 2 +-
.../header_actions/header_actions.tsx | 2 +-
.../hover_actions/use_hover_action_items.tsx | 4 +--
.../breadcrumbs/use_breadcrumbs_nav.ts | 2 +-
.../common/components/search_bar/index.tsx | 2 +-
.../common/components/sourcerer/temporary.tsx | 4 +--
.../components/super_date_picker/index.tsx | 2 +-
.../common/components/top_n/index.test.tsx | 2 +-
.../public/common/components/top_n/index.tsx | 6 ++--
.../common/containers/sourcerer/index.tsx | 2 +-
.../timeline/use_init_timeline_url_param.ts | 4 +--
...query_timeline_by_id_on_url_change.test.ts | 2 +-
.../use_query_timeline_by_id_on_url_change.ts | 4 +--
.../timeline/use_sync_timeline_url_param.ts | 4 +--
.../timeline/use_timeline_save_prompt.ts | 2 +-
.../hooks/use_resolve_conflict.test.tsx | 2 +-
.../common/hooks/use_resolve_conflict.tsx | 6 ++--
.../common/hooks/use_resolve_redirect.test.ts | 2 +-
.../common/hooks/use_resolve_redirect.ts | 6 ++--
.../lib/cell_actions/add_to_timeline.tsx | 2 +-
.../public/common/lib/telemetry/middleware.ts | 2 +-
.../public/common/mock/timeline_results.ts | 4 +--
.../public/common/mock/utils.ts | 2 +-
.../store/data_table/epic_local_storage.ts | 4 +--
.../public/common/store/epic.ts | 13 ++++---
.../public/common/store/reducer.ts | 2 +-
.../public/common/store/store.ts | 8 ++---
.../public/common/store/types.ts | 2 +-
.../utils/timeline/use_timeline_click.tsx | 2 +-
.../components/alerts_table/actions.test.tsx | 2 +-
.../components/alerts_table/actions.tsx | 2 +-
.../use_add_bulk_to_timeline.tsx | 2 +-
.../use_investigate_in_timeline.tsx | 4 +--
.../components/alerts_table/types.ts | 2 +-
.../components/rules/query_bar/index.tsx | 2 +-
.../rules/use_rule_from_timeline.tsx | 2 +-
.../explore/users/pages/details/index.tsx | 2 +-
.../components/analyzer_preview_container.tsx | 2 +-
.../components/session_preview_container.tsx | 2 +-
.../security_solution/public/helpers.tsx | 2 +-
.../plugins/security_solution/public/index.ts | 2 +-
.../hooks/use_navigate_to_timeline.test.ts | 2 +-
.../hooks/use_navigate_to_timeline.tsx | 2 +-
.../components/recent_timelines/index.tsx | 2 +-
.../use_investigate_in_timeline.ts | 4 +--
.../action_menu/save_timeline_modal.tsx | 2 +-
.../flyout/add_to_case_button/index.tsx | 6 ++--
.../flyout/header/active_timelines.tsx | 2 +-
.../components/flyout/header/index.tsx | 4 +--
.../components/flyout/header/selectors.ts | 2 +-
.../components/flyout/index.test.tsx | 2 +-
.../timelines/components/flyout/index.tsx | 2 +-
.../timelines/components/flyout/selectors.ts | 2 +-
.../components/formatted_ip/index.test.tsx | 6 ++--
.../components/graph_overlay/index.tsx | 4 +--
.../components/open_timeline/helpers.test.ts | 6 ++--
.../components/open_timeline/helpers.ts | 6 ++--
.../components/open_timeline/index.tsx | 6 ++--
.../open_timeline/note_previews/index.tsx | 2 +-
.../open_timeline_modal/index.tsx | 2 +-
.../components/open_timeline/types.ts | 2 +-
.../row_renderers_browser/index.tsx | 6 ++--
.../hooks/use_detail_panel.test.tsx | 4 +--
.../side_panel/hooks/use_detail_panel.tsx | 4 +--
.../timelines/components/side_panel/index.tsx | 4 +--
.../body/column_headers/column_header.tsx | 2 +-
.../body/column_headers/header/index.test.tsx | 2 +-
.../body/column_headers/header/index.tsx | 2 +-
.../body/column_headers/header/selectors.tsx | 2 +-
.../body/column_headers/index.test.tsx | 2 +-
.../timeline/body/column_headers/index.tsx | 2 +-
.../timeline/body/events/stateful_event.tsx | 4 +--
.../components/timeline/body/index.test.tsx | 2 +-
.../components/timeline/body/index.tsx | 4 +--
.../body/renderers/host_name.test.tsx | 6 ++--
.../body/renderers/user_name.test.tsx | 6 ++--
.../timeline/body/selectors/index.ts | 2 +-
.../add_data_provider_popover.tsx | 2 +-
.../timeline/data_providers/helpers.tsx | 2 +-
.../timeline/data_providers/index.tsx | 8 ++---
.../data_providers/provider_item_badge.tsx | 4 +--
.../data_providers/providers.test.tsx | 2 +-
.../timeline/data_providers/providers.tsx | 2 +-
.../timeline/eql_tab_content/index.tsx | 6 ++--
.../timeline/esql_tab_content/index.tsx | 6 ++--
.../components/timeline/footer/index.tsx | 2 +-
.../timeline/graph_tab_content/index.tsx | 2 +-
.../timelines/components/timeline/index.tsx | 4 +--
.../components/timeline/kpi/kpi_container.tsx | 4 +--
.../timeline/notes_tab_content/index.tsx | 2 +-
.../timeline/notes_tab_content/selectors.ts | 2 +-
.../timeline/pinned_tab_content/index.tsx | 6 ++--
.../timeline/properties/helpers.test.tsx | 2 +-
.../timeline/properties/helpers.tsx | 4 +--
.../properties/use_create_timeline.tsx | 2 +-
.../timeline/query_bar/eql/index.tsx | 2 +-
.../timeline/query_bar/eql/selectors.tsx | 2 +-
.../components/timeline/query_bar/index.tsx | 4 +--
.../query_tab_content/header/index.tsx | 4 +--
.../query_tab_content/header/selectors.ts | 2 +-
.../timeline/query_tab_content/index.tsx | 6 ++--
.../timeline/search_or_filter/helpers.tsx | 2 +-
.../timeline/search_or_filter/index.tsx | 8 ++---
.../search_or_filter/search_or_filter.tsx | 2 +-
.../session_tab_content/use_session_view.tsx | 4 +--
.../timeline/tabs_content/index.tsx | 4 +--
.../timeline/tabs_content/selectors.ts | 2 +-
.../public/timelines/containers/index.tsx | 2 +-
.../public/timelines/index.ts | 4 +--
.../timelines/store/{timeline => }/actions.ts | 12 +++----
.../store/{timeline => }/defaults.ts | 8 ++---
.../store/{timeline => }/epic.test.ts | 6 ++--
.../timelines/store/{timeline => }/epic.ts | 18 +++++-----
.../store/{timeline => }/epic_changed.ts | 0
...c_dispatcher_timeline_persistence_queue.ts | 0
.../store/{timeline => }/epic_favorite.ts | 10 +++---
.../store/{timeline => }/epic_note.ts | 10 +++---
.../store/{timeline => }/epic_pinned_event.ts | 8 ++---
.../store/{timeline => }/helpers.test.ts | 29 +++++++--------
.../timelines/store/{timeline => }/helpers.ts | 36 ++++++++-----------
.../timelines/store/{timeline => }/index.ts | 0
.../{timeline => }/manage_timeline_id.tsx | 0
.../timelines/store/{timeline => }/model.ts | 10 +++---
.../{timeline => }/my_epic_timeline_id.ts | 0
.../timelines/store/{timeline => }/reducer.ts | 2 +-
.../store/{timeline => }/selectors.ts | 2 +-
.../timelines/store/{timeline => }/types.ts | 10 +++---
154 files changed, 294 insertions(+), 306 deletions(-)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/actions.ts (95%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/defaults.ts (87%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic.test.ts (97%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic.ts (96%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic_changed.ts (100%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic_dispatcher_timeline_persistence_queue.ts (100%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic_favorite.ts (92%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic_note.ts (93%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/epic_pinned_event.ts (94%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/helpers.test.ts (98%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/helpers.ts (97%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/index.ts (100%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/manage_timeline_id.tsx (100%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/model.ts (96%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/my_epic_timeline_id.ts (100%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/reducer.ts (99%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/selectors.ts (97%)
rename x-pack/plugins/security_solution/public/timelines/store/{timeline => }/types.ts (87%)
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.test.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.test.ts
index dade311fa6b49..3a47134531d37 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.test.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.test.ts
@@ -7,7 +7,7 @@
import type { SecurityAppStore } from '../../../common/store/types';
import { TimelineId } from '../../../../common/types';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import { createAddToTimelineCellActionFactory } from './add_to_timeline';
import type { CellActionExecutionContext } from '@kbn/cell-actions';
import { GEO_FIELD_TYPE } from '../../../timelines/components/timeline/body/renderers/constants';
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.ts
index 9ce248701a75d..1b40784dcec4d 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/add_to_timeline.ts
@@ -15,7 +15,7 @@ import {
} from '@kbn/cell-actions/src/actions/utils';
import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations';
import type { KBN_FIELD_TYPES } from '@kbn/field-types';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import { TimelineId } from '../../../../common/types';
import type { SecurityAppStore } from '../../../common/store';
import { fieldHasCellActions } from '../../utils';
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.test.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.test.ts
index d8c83e6a336d9..ee1d1ec579f12 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.test.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.test.ts
@@ -7,12 +7,12 @@
import type { SecurityAppStore } from '../../../common/store/types';
import { TimelineId } from '../../../../common/types';
-import { addProvider, showTimeline } from '../../../timelines/store/timeline/actions';
+import { addProvider, showTimeline } from '../../../timelines/store/actions';
import { createInvestigateInNewTimelineCellActionFactory } from './investigate_in_new_timeline';
import type { CellActionExecutionContext } from '@kbn/cell-actions';
import { GEO_FIELD_TYPE } from '../../../timelines/components/timeline/body/renderers/constants';
import { createStartServicesMock } from '../../../common/lib/kibana/kibana_react.mock';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
import { KBN_FIELD_TYPES } from '@kbn/field-types';
const services = createStartServicesMock();
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.ts
index 0ba3cf3ffc8a8..2c9dd401d415a 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/cell_action/investigate_in_new_timeline.ts
@@ -14,8 +14,8 @@ import {
filterOutNullableValues,
} from '@kbn/cell-actions/src/actions/utils';
import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations';
-import { timelineActions } from '../../../timelines/store/timeline';
-import { addProvider, showTimeline } from '../../../timelines/store/timeline/actions';
+import { timelineActions } from '../../../timelines/store';
+import { addProvider, showTimeline } from '../../../timelines/store/actions';
import { TimelineId } from '../../../../common/types';
import type { SecurityAppStore } from '../../../common/store';
import { fieldHasCellActions } from '../../utils';
@@ -29,7 +29,7 @@ import { createDataProviders, isValidDataProviderField } from '../data_provider'
import { SecurityCellActionType } from '../../constants';
import type { StartServices } from '../../../types';
import type { SecurityCellAction } from '../../types';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
export const createInvestigateInNewTimelineCellActionFactory = createCellActionFactory(
({
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/discover/add_to_timeline.test.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/discover/add_to_timeline.test.ts
index f8c62857e3e24..4374bf70b19bc 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/discover/add_to_timeline.test.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/discover/add_to_timeline.test.ts
@@ -7,7 +7,7 @@
import type { SecurityAppStore } from '../../../common/store/types';
import { TimelineId } from '../../../../common/types';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import { createAddToTimelineDiscoverCellActionFactory } from './add_to_timeline';
import type { CellActionExecutionContext } from '@kbn/cell-actions';
import { GEO_FIELD_TYPE } from '../../../timelines/components/timeline/body/renderers/constants';
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.test.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.test.ts
index ebb1f40061a72..976d0f13efab0 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.test.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.test.ts
@@ -14,7 +14,7 @@ import { KibanaServices } from '../../../common/lib/kibana';
import { APP_UI_ID } from '../../../../common/constants';
import type { DataProvider } from '../../../../common/types';
import { TimelineId, EXISTS_OPERATOR } from '../../../../common/types';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
jest.mock('../../../common/lib/kibana');
diff --git a/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.ts b/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.ts
index 4032a2fe1fe8f..1a536c34d77a4 100644
--- a/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.ts
+++ b/x-pack/plugins/security_solution/public/actions/add_to_timeline/lens/add_to_timeline.ts
@@ -10,7 +10,7 @@ import { isErrorEmbeddable, isFilterableEmbeddable } from '@kbn/embeddable-plugi
import { createAction } from '@kbn/ui-actions-plugin/public';
import { KibanaServices } from '../../../common/lib/kibana';
import type { SecurityAppStore } from '../../../common/store/types';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import type { DataProvider } from '../../../../common/types';
import { EXISTS_OPERATOR, TimelineId } from '../../../../common/types';
import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils';
diff --git a/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_in.ts b/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_in.ts
index 905da379d01ff..1b65b608f43a2 100644
--- a/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_in.ts
+++ b/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_in.ts
@@ -15,7 +15,7 @@ import {
import type { KBN_FIELD_TYPES } from '@kbn/field-types';
import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations';
import type { SecurityAppStore } from '../../../common/store';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import { fieldHasCellActions } from '../../utils';
import { TimelineId } from '../../../../common/types';
import { isTimelineScope } from '../../../helpers';
diff --git a/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_out.ts b/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_out.ts
index 38c2e52b7c7c7..56eb27433fee5 100644
--- a/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_out.ts
+++ b/x-pack/plugins/security_solution/public/actions/filter/cell_action/filter_out.ts
@@ -17,7 +17,7 @@ import type { KBN_FIELD_TYPES } from '@kbn/field-types';
import { fieldHasCellActions } from '../../utils';
import type { SecurityAppStore } from '../../../common/store';
import type { StartServices } from '../../../types';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import { TimelineId } from '../../../../common/types';
import { isTimelineScope } from '../../../helpers';
import type { SecurityCellAction } from '../../types';
diff --git a/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts b/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts
index 78a0a9d46ff21..461356dc7224d 100644
--- a/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts
+++ b/x-pack/plugins/security_solution/public/actions/filter/lens/create_action.ts
@@ -16,7 +16,7 @@ import type { CellValueContext } from '@kbn/embeddable-plugin/public';
import { createAction } from '@kbn/ui-actions-plugin/public';
import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations';
import { i18n } from '@kbn/i18n';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils';
import { TimelineId } from '../../../../common/types';
import { DefaultCellActionTypes } from '../../constants';
diff --git a/x-pack/plugins/security_solution/public/actions/toggle_column/cell_action/toggle_column.ts b/x-pack/plugins/security_solution/public/actions/toggle_column/cell_action/toggle_column.ts
index 6a1d73ffa1311..2a2926f3f6a27 100644
--- a/x-pack/plugins/security_solution/public/actions/toggle_column/cell_action/toggle_column.ts
+++ b/x-pack/plugins/security_solution/public/actions/toggle_column/cell_action/toggle_column.ts
@@ -15,8 +15,8 @@ import {
import { fieldHasCellActions } from '../../utils';
import type { SecurityAppStore } from '../../../common/store';
import { getScopedActions, isInTableScope, isTimelineScope } from '../../../helpers';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineDefaults } from '../../../timelines/store/defaults';
+import { timelineSelectors } from '../../../timelines/store';
import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants';
import type { SecurityCellAction } from '../../types';
import { SecurityCellActionType } from '../../constants';
diff --git a/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx b/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx
index e5a12721a6292..d02eb41605e3a 100644
--- a/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx
+++ b/x-pack/plugins/security_solution/public/app/home/global_header/index.tsx
@@ -21,8 +21,8 @@ import { useKibana } from '../../../common/lib/kibana';
import { isDetectionsPath, isDashboardViewPath } from '../../../helpers';
import { Sourcerer } from '../../../common/components/sourcerer';
import { TimelineId } from '../../../../common/types/timeline';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineDefaults } from '../../../timelines/store/defaults';
+import { timelineSelectors } from '../../../timelines/store';
import { useShallowEqualSelector } from '../../../common/hooks/use_selector';
import { getScopeFromPath, showSourcererByPath } from '../../../common/containers/sourcerer';
import { useAddIntegrationsUrl } from '../../../common/hooks/use_add_integrations_url';
diff --git a/x-pack/plugins/security_solution/public/app/home/index.test.tsx b/x-pack/plugins/security_solution/public/app/home/index.test.tsx
index fc62a8236f9cc..8fce33967e151 100644
--- a/x-pack/plugins/security_solution/public/app/home/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/app/home/index.test.tsx
@@ -29,8 +29,8 @@ import type { Filter } from '@kbn/es-query';
import { createStore } from '../../common/store';
import type { TimeRange, UrlInputsModel } from '../../common/store/inputs/model';
import { SecurityPageName } from '../types';
-import type { TimelineUrl } from '../../timelines/store/timeline/model';
-import { timelineDefaults } from '../../timelines/store/timeline/defaults';
+import type { TimelineUrl } from '../../timelines/store/model';
+import { timelineDefaults } from '../../timelines/store/defaults';
import { URL_PARAM_KEY } from '../../common/hooks/use_url_state';
import { InputsModelId } from '../../common/store/inputs/constants';
import { TopValuesPopoverService } from '../components/top_values_popover/top_values_popover_service';
@@ -98,7 +98,7 @@ jest.mock('../../timelines/components/open_timeline/helpers', () => {
const mockGetTimeline = jest.fn();
-jest.mock('../../timelines/store/timeline', () => ({
+jest.mock('../../timelines/store', () => ({
timelineSelectors: {
getTimelineByIdSelector: () => mockGetTimeline,
},
diff --git a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx
index 6059ef63ae6f1..1804c837c4f1d 100644
--- a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx
@@ -17,7 +17,7 @@ import type { Note } from '../../common/lib/note';
import { appActions } from '../../common/store/actions';
import { TimelineId } from '../../../common/types';
import { updateAndAssociateNode } from '../../timelines/components/notes/helpers';
-import { timelineActions } from '../../timelines/store/timeline';
+import { timelineActions } from '../../timelines/store';
import * as i18n from './translations';
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
diff --git a/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx b/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx
index 114d5deb5f3ec..fe2c23b8f60b1 100644
--- a/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx
+++ b/x-pack/plugins/security_solution/public/assistant/send_to_timeline/index.tsx
@@ -33,7 +33,7 @@ import {
showTimeline,
updateDataView,
updateEqlOptions,
-} from '../../timelines/store/timeline/actions';
+} from '../../timelines/store/actions';
import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context';
import { useShowTimeline } from '../../common/utils/timeline/use_show_timeline';
diff --git a/x-pack/plugins/security_solution/public/cases/components/use_insert_timeline/index.tsx b/x-pack/plugins/security_solution/public/cases/components/use_insert_timeline/index.tsx
index e12d973d0be6e..cd5b4bcde7822 100644
--- a/x-pack/plugins/security_solution/public/cases/components/use_insert_timeline/index.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/use_insert_timeline/index.tsx
@@ -11,9 +11,9 @@ import { isEmpty } from 'lodash/fp';
import { getTimelineUrl, useFormatUrl } from '../../../common/components/link_to';
import { useShallowEqualSelector } from '../../../common/hooks/use_selector';
-import { timelineSelectors, timelineActions } from '../../../timelines/store/timeline';
+import { timelineSelectors, timelineActions } from '../../../timelines/store';
import { SecurityPageName } from '../../../app/types';
-import { setInsertTimeline } from '../../../timelines/store/timeline/actions';
+import { setInsertTimeline } from '../../../timelines/store/actions';
export interface UseInsertTimelineReturn {
handleOnTimelineChange: (title: string, id: string | null, graphEventId?: string) => void;
diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx
index ab5b170e423c0..ba920046837ff 100644
--- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx
+++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx
@@ -28,7 +28,7 @@ import {
ENABLE_EXPANDABLE_FLYOUT_SETTING,
SecurityPageName,
} from '../../../common/constants';
-import { timelineActions } from '../../timelines/store/timeline';
+import { timelineActions } from '../../timelines/store';
import { useSourcererDataView } from '../../common/containers/sourcerer';
import { SourcererScopeName } from '../../common/store/sourcerer/model';
import { CaseDetailsRefreshContext } from '../../common/components/endpoint/host_isolation/endpoint_host_isolation_cases_context';
diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx
index 93a29b9ea4436..e729ccce92578 100644
--- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx
@@ -11,7 +11,7 @@ import { useDispatch } from 'react-redux';
import { useExpandableFlyoutContext } from '@kbn/expandable-flyout';
import { dataTableActions, TableId } from '@kbn/securitysolution-data-table';
import { useUiSetting$ } from '@kbn/kibana-react-plugin/public';
-import { timelineActions } from '../../../../timelines/store/timeline';
+import { timelineActions } from '../../../../timelines/store';
import { ENABLE_EXPANDABLE_FLYOUT_SETTING } from '../../../../../common/constants';
import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/right';
import type {
diff --git a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx
index fddf6a1afc6e8..b2d1ac052a1e0 100644
--- a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.test.tsx
@@ -23,7 +23,7 @@ import { useKibana } from '../../lib/kibana';
import type { State } from '../../store';
import { createStore } from '../../store';
import { TimelineId } from '../../../../common/types';
-import * as timelineActions from '../../../timelines/store/timeline/actions';
+import * as timelineActions from '../../../timelines/store/actions';
import type { ComponentType, FC, PropsWithChildren } from 'react';
import React from 'react';
import type { DataView } from '@kbn/data-views-plugin/common';
diff --git a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx
index cde218b6e450f..3c8ab819527b6 100644
--- a/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/discover_in_timeline/use_discover_in_timeline_actions.tsx
@@ -15,9 +15,9 @@ import type { DiscoverAppState } from '@kbn/discover-plugin/public/application/m
import type { TimeRange } from '@kbn/es-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { defaultHeaders } from '@kbn/securitysolution-data-table';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import { TimelineId } from '../../../../common/types';
-import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineActions, timelineSelectors } from '../../../timelines/store';
import { useAppToasts } from '../../hooks/use_app_toasts';
import { useShallowEqualSelector } from '../../hooks/use_selector';
import { useKibana } from '../../lib/kibana';
diff --git a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx
index a1455f7e5cc09..437309762732d 100644
--- a/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx
@@ -16,7 +16,7 @@ import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid';
import type { BrowserFields } from '../../containers/source';
import { dragAndDropSelectors } from '../../store';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import type { IdToDataProvider } from '../../store/drag_and_drop/model';
import type { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
import { reArrangeProviders } from '../../../timelines/components/timeline/data_providers/helpers';
@@ -39,7 +39,7 @@ import {
} from './helpers';
import { useDeepEqualSelector } from '../../hooks/use_selector';
import { useKibana } from '../../lib/kibana';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import { defaultAlertsHeaders } from '../events_viewer/default_alert_headers';
// @ts-expect-error
diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/route_capture.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/route_capture.tsx
index 1fd12db245fcc..e1d0751337fbf 100644
--- a/x-pack/plugins/security_solution/public/common/components/endpoint/route_capture.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/endpoint/route_capture.tsx
@@ -10,7 +10,7 @@ import { useLocation } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { TimelineId } from '../../../../common/types';
import type { AppLocation } from '../../../../common/endpoint/types';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
/**
* This component should be used above all routes, but below the Provider.
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx
index 8f5fdf54efdc9..7d3f5feb93f32 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_fields_browser.tsx
@@ -22,12 +22,12 @@ import {
import { dataTableSelectors, tableDefaults } from '@kbn/securitysolution-data-table';
import { isInTableScope, isTimelineScope } from '../../../helpers';
import { ADD_TIMELINE_BUTTON_CLASS_NAME } from '../../../timelines/components/flyout/add_timeline_button';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import type { BrowserFields } from '../../containers/source';
import { getAllFieldsByName } from '../../containers/source';
import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy/timeline';
import { getColumnHeaders } from '../../../timelines/components/timeline/body/column_headers/helpers';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import { getColumns } from './columns';
import { EVENT_FIELDS_TABLE_CLASS_NAME, onEventDetailsTabKeyPressed, search } from './helpers';
import { useDeepEqualSelector } from '../../hooks/use_selector';
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/overview/index.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/overview/index.tsx
index b33f777dcff41..762671896b36e 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/overview/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/overview/index.tsx
@@ -30,7 +30,7 @@ import { OverviewCardWithActions, OverviewCard } from './overview_card';
import { StatusPopoverButton } from './status_popover_button';
import { SeverityBadge } from '../../../../detections/components/rules/severity_badge';
import { useThrottledResizeObserver } from '../../utils';
-import { isNotNull } from '../../../../timelines/store/timeline/helpers';
+import { isNotNull } from '../../../../timelines/store/helpers';
export const NotGrowingFlexGroup = euiStyled(EuiFlexGroup)`
flex-grow: 0;
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/investigate_in_timeline_button.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/table/investigate_in_timeline_button.tsx
index ad464585ec682..86f005e720f46 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/table/investigate_in_timeline_button.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/investigate_in_timeline_button.tsx
@@ -15,7 +15,7 @@ import { sourcererSelectors } from '../../../store';
import { InputsModelId } from '../../../store/inputs/constants';
import type { TimeRange } from '../../../store/inputs/model';
import { inputsActions } from '../../../store/inputs';
-import { updateProviders, setFilters } from '../../../../timelines/store/timeline/actions';
+import { updateProviders, setFilters } from '../../../../timelines/store/actions';
import { sourcererActions } from '../../../store/actions';
import { SourcererScopeName } from '../../../store/sourcerer/model';
import type { DataProvider } from '../../../../../common/types';
diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
index 12cfa2467f3fc..156604160be74 100644
--- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_step.tsx
@@ -14,8 +14,8 @@ import { FormattedMessage } from '@kbn/i18n-react';
import styled from 'styled-components';
import { useShallowEqualSelector } from '../../hooks/use_selector';
import { TimelineId } from '../../../../common/types';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineDefaults } from '../../../timelines/store/defaults';
+import { timelineSelectors } from '../../../timelines/store';
import { useTourContext } from './tour';
import { AlertsCasesTourSteps, SecurityStepId, securityTourConfig } from './tour_config';
diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx
index e5c3dc3832953..881658c521a8e 100644
--- a/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/header_actions/actions.tsx
@@ -18,18 +18,18 @@ import {
} from '../../../timelines/components/timeline/body/helpers';
import { getScopedActions, isTimelineScope } from '../../../helpers';
import { useIsInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver';
-import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineActions, timelineSelectors } from '../../../timelines/store';
import type { ActionProps, OnPinEvent } from '../../../../common/types';
import { TimelineId } from '../../../../common/types';
import { AddEventNoteAction } from './add_note_icon_item';
import { PinEventAction } from './pin_event_action';
import { useShallowEqualSelector } from '../../hooks/use_selector';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import { useStartTransaction } from '../../lib/apm/use_start_transaction';
import { useLicense } from '../../hooks/use_license';
import { useGlobalFullScreen, useTimelineFullScreen } from '../../containers/use_full_screen';
import { ALERTS_ACTIONS } from '../../lib/apm/user_actions';
-import { setActiveTabTimeline } from '../../../timelines/store/timeline/actions';
+import { setActiveTabTimeline } from '../../../timelines/store/actions';
import { EventsTdContent } from '../../../timelines/components/timeline/styles';
import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features';
import { AlertContextMenu } from '../../../detections/components/alerts_table/timeline_actions/alert_context_menu';
diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx
index 6a8f06696bada..c8ab77c05fdbe 100644
--- a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.test.tsx
@@ -12,7 +12,7 @@ import { mockTriggersActionsUi } from '../../mock/mock_triggers_actions_ui_plugi
import type { ColumnHeaderOptions, HeaderActionProps } from '../../../../common/types';
import { TimelineTabs } from '../../../../common/types';
import { HeaderActions } from './header_actions';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
import { getColumnHeader } from '../../../timelines/components/timeline/body/column_headers/helpers';
jest.mock('../../../timelines/components/row_renderers_browser', () => ({
diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx
index 231ed8f8b4e66..cbac23af41205 100644
--- a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx
@@ -16,7 +16,7 @@ import { TimelineTabs, TimelineId } from '../../../../common/types';
import { isFullScreen } from '../../../timelines/components/timeline/body/column_headers';
import { isActiveTimeline } from '../../../helpers';
import { getColumnHeader } from '../../../timelines/components/timeline/body/column_headers/helpers';
-import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineActions, timelineSelectors } from '../../../timelines/store';
import { useDeepEqualSelector } from '../../hooks/use_selector';
import { useGlobalFullScreen, useTimelineFullScreen } from '../../containers/use_full_screen';
import { useKibana } from '../../lib/kibana';
diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx
index 4acebe2d3a12c..95c69b4e5c4aa 100644
--- a/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/use_hover_action_items.tsx
@@ -14,13 +14,13 @@ import { isEmpty } from 'lodash';
import { FilterManager } from '@kbn/data-plugin/public';
import { useDispatch } from 'react-redux';
import { isActiveTimeline } from '../../../helpers';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import { useKibana } from '../../lib/kibana';
import { allowTopN } from '../drag_and_drop/helpers';
import type { ColumnHeaderOptions, DataProvider } from '../../../../common/types/timeline';
import { TimelineId } from '../../../../common/types/timeline';
import { ShowTopNButton } from './actions/show_top_n';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
import { useDeepEqualSelector } from '../../hooks/use_selector';
export interface UseHoverActionItemsProps {
dataProvider?: DataProvider | DataProvider[];
diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts
index 5a467464670a5..7825435fafcad 100644
--- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts
+++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts
@@ -12,7 +12,7 @@ import type { ChromeBreadcrumb } from '@kbn/core/public';
import type { Dispatch } from 'redux';
import { SecurityPageName } from '../../../../app/types';
import type { RouteSpyState } from '../../../utils/route/types';
-import { timelineActions } from '../../../../timelines/store/timeline';
+import { timelineActions } from '../../../../timelines/store';
import { TimelineId } from '../../../../../common/types/timeline';
import type { GetSecuritySolutionUrl } from '../../link_to';
import { useGetSecuritySolutionUrl } from '../../link_to';
diff --git a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
index c9906c6e70eac..af4c0aa7b0c19 100644
--- a/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/search_bar/index.tsx
@@ -35,7 +35,7 @@ import {
startSelector,
toStrSelector,
} from './selectors';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
import { useKibana } from '../../lib/kibana';
import { usersActions } from '../../../explore/users/store';
import { hostsActions } from '../../../explore/hosts/store';
diff --git a/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx b/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx
index 1c2c73abcc042..63bdd45073200 100644
--- a/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/sourcerer/temporary.tsx
@@ -22,9 +22,9 @@ import { Blockquote, ResetButton } from './helpers';
import { UpdateDefaultDataViewModal } from './update_default_data_view_modal';
import { TimelineId } from '../../../../common/types';
import { TimelineType } from '../../../../common/api/timeline';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import { useDeepEqualSelector } from '../../hooks/use_selector';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import {
BadCurrentPatternsMessage,
CurrentPatternsMessage,
diff --git a/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx b/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx
index b79f9c736f5cc..d37e0c0515ae9 100644
--- a/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/super_date_picker/index.tsx
@@ -24,7 +24,7 @@ import deepEqual from 'fast-deep-equal';
import { isQueryInput } from '../../store/inputs/helpers';
import { DEFAULT_TIMEPICKER_QUICK_RANGES } from '../../../../common/constants';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
import { useUiSetting$ } from '../../lib/kibana';
import type { inputsModel, State } from '../../store';
import { inputsActions } from '../../store/actions';
diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx
index eed95e5caa9cb..9a329d369e7e4 100644
--- a/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.test.tsx
@@ -42,7 +42,7 @@ jest.mock('react-router-dom', () => {
jest.mock('../link_to');
jest.mock('../../lib/kibana');
-jest.mock('../../../timelines/store/timeline/actions');
+jest.mock('../../../timelines/store/actions');
jest.mock('../visualization_actions/actions');
jest.mock('../visualization_actions/lens_embeddable');
const field = 'process.name';
diff --git a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
index 45cb33aa199b5..d845f2604c69b 100644
--- a/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/top_n/index.tsx
@@ -19,9 +19,9 @@ import { useKibana } from '../../lib/kibana';
import { combineQueries } from '../../lib/kuery';
import type { inputsModel, State } from '../../store';
import { inputsSelectors } from '../../store';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
-import { timelineSelectors } from '../../../timelines/store/timeline';
-import type { TimelineModel } from '../../../timelines/store/timeline/model';
+import { timelineDefaults } from '../../../timelines/store/defaults';
+import { timelineSelectors } from '../../../timelines/store';
+import type { TimelineModel } from '../../../timelines/store/model';
import { getOptions, isDetectionsAlertsTable } from './helpers';
import { TopN } from './top_n';
diff --git a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx
index de784c876fd66..2e9c6cf796e57 100644
--- a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx
@@ -18,7 +18,7 @@ import type {
} from '../../store/sourcerer/model';
import { SourcererScopeName } from '../../store/sourcerer/model';
import { useUserInfo } from '../../../detections/components/user_info';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import { timelineSelectors } from '../../../timelines/store';
import {
ALERTS_PATH,
HOSTS_PATH,
diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts
index 4d6ef73c643de..1a3058cb138e5 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_init_timeline_url_param.ts
@@ -15,8 +15,8 @@ import {
dispatchUpdateTimeline,
queryTimelineById,
} from '../../../timelines/components/open_timeline/helpers';
-import type { TimelineUrl } from '../../../timelines/store/timeline/model';
-import { timelineActions } from '../../../timelines/store/timeline';
+import type { TimelineUrl } from '../../../timelines/store/model';
+import { timelineActions } from '../../../timelines/store';
import { URL_PARAM_KEY } from '../use_url_state';
export const useInitTimelineFromUrlParam = () => {
diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.test.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.test.ts
index 3966ebc6697b2..ef5fe57f16e98 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.test.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.test.ts
@@ -8,7 +8,7 @@
import { queryTimelineById } from '../../../timelines/components/open_timeline/helpers';
import { useQueryTimelineByIdOnUrlChange } from './use_query_timeline_by_id_on_url_change';
import { renderHook } from '@testing-library/react-hooks';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
jest.mock('../../../timelines/components/open_timeline/helpers');
diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts
index e56131cd2603c..a7ecab2d5bb50 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_query_timeline_by_id_on_url_change.ts
@@ -11,8 +11,8 @@ import { useLocation } from 'react-router-dom';
import usePrevious from 'react-use/lib/usePrevious';
import { useDispatch } from 'react-redux';
import { safeDecode } from '@kbn/rison';
-import type { TimelineUrl } from '../../../timelines/store/timeline/model';
-import { timelineActions, timelineSelectors } from '../../../timelines/store/timeline';
+import type { TimelineUrl } from '../../../timelines/store/model';
+import { timelineActions, timelineSelectors } from '../../../timelines/store';
import { TimelineId, TimelineTabs } from '../../../../common/types';
import { useShallowEqualSelector } from '../use_selector';
diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_sync_timeline_url_param.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_sync_timeline_url_param.ts
index f016cbfd57cc8..4d3aa88c4eaf5 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_sync_timeline_url_param.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_sync_timeline_url_param.ts
@@ -8,8 +8,8 @@
import { useEffect, useMemo } from 'react';
import { useUpdateUrlParam } from '../../utils/global_query_string';
-import type { TimelineUrl } from '../../../timelines/store/timeline/model';
-import { timelineSelectors } from '../../../timelines/store/timeline';
+import type { TimelineUrl } from '../../../timelines/store/model';
+import { timelineSelectors } from '../../../timelines/store';
import { TimelineId } from '../../../../common/types';
import { useShallowEqualSelector } from '../use_selector';
import { URL_PARAM_KEY } from '../use_url_state';
diff --git a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts
index 54422da6fe038..4eb7adf15f52e 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts
@@ -17,7 +17,7 @@ import { useKibana } from '../../lib/kibana';
import { useDeepEqualSelector } from '../use_selector';
import { APP_ID, APP_PATH } from '../../../../common/constants';
import { getTimelineShowStatusByIdSelector } from '../../../timelines/components/flyout/selectors';
-import { timelineActions } from '../../../timelines/store/timeline';
+import { timelineActions } from '../../../timelines/store';
import {
UNSAVED_TIMELINE_SAVE_PROMPT,
UNSAVED_TIMELINE_SAVE_PROMPT_TITLE,
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.test.tsx b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.test.tsx
index e69f70234153e..3e3b28cd028f7 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.test.tsx
@@ -20,7 +20,7 @@ jest.mock('react-router-dom', () => {
});
jest.mock('../lib/kibana');
jest.mock('./use_selector');
-jest.mock('../../timelines/store/timeline', () => ({
+jest.mock('../../timelines/store', () => ({
timelineSelectors: {
getTimelineByIdSelector: () => jest.fn(),
},
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx
index 40eace1bd6e6e..c73b21c3b8418 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx
+++ b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx
@@ -11,9 +11,9 @@ import { EuiSpacer } from '@elastic/eui';
import { safeDecode, encode } from '@kbn/rison';
import { useDeepEqualSelector } from './use_selector';
import { TimelineId } from '../../../common/types/timeline';
-import { timelineSelectors } from '../../timelines/store/timeline';
-import type { TimelineUrl } from '../../timelines/store/timeline/model';
-import { timelineDefaults } from '../../timelines/store/timeline/defaults';
+import { timelineSelectors } from '../../timelines/store';
+import type { TimelineUrl } from '../../timelines/store/model';
+import { timelineDefaults } from '../../timelines/store/defaults';
import { useKibana } from '../lib/kibana';
import { URL_PARAM_KEY } from './use_url_state';
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.test.ts b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.test.ts
index 6aeb2a8b42d83..113a18dad705c 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.test.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.test.ts
@@ -21,7 +21,7 @@ jest.mock('react-router-dom', () => {
});
jest.mock('../lib/kibana');
jest.mock('./use_selector');
-jest.mock('../../timelines/store/timeline', () => ({
+jest.mock('../../timelines/store', () => ({
timelineSelectors: {
getTimelineByIdSelector: () => jest.fn(),
},
diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.ts b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.ts
index e771995e25031..35d9b4a365f13 100644
--- a/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.ts
+++ b/x-pack/plugins/security_solution/public/common/hooks/use_resolve_redirect.ts
@@ -10,10 +10,10 @@ import { useLocation } from 'react-router-dom';
import { safeDecode, encode } from '@kbn/rison';
import { useDeepEqualSelector } from './use_selector';
import { TimelineId } from '../../../common/types/timeline';
-import { timelineSelectors } from '../../timelines/store/timeline';
-import { timelineDefaults } from '../../timelines/store/timeline/defaults';
+import { timelineSelectors } from '../../timelines/store';
+import { timelineDefaults } from '../../timelines/store/defaults';
import { useKibana } from '../lib/kibana';
-import type { TimelineUrl } from '../../timelines/store/timeline/model';
+import type { TimelineUrl } from '../../timelines/store/model';
import { URL_PARAM_KEY } from './use_url_state';
/**
diff --git a/x-pack/plugins/security_solution/public/common/lib/cell_actions/add_to_timeline.tsx b/x-pack/plugins/security_solution/public/common/lib/cell_actions/add_to_timeline.tsx
index 3686a33814d7f..9e970bea2e639 100644
--- a/x-pack/plugins/security_solution/public/common/lib/cell_actions/add_to_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/common/lib/cell_actions/add_to_timeline.tsx
@@ -20,7 +20,7 @@ import {
} from '../../../timelines/components/timeline/data_providers/data_provider';
import { escapeDataProviderId } from '../../components/drag_and_drop/helpers';
import { EmptyComponent, useKibanaServices } from './helpers';
-import { addProvider } from '../../../timelines/store/timeline/actions';
+import { addProvider } from '../../../timelines/store/actions';
export const getAddToTimelineCellAction = ({
data,
diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/middleware.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/middleware.ts
index 0085cdc999ac7..658f5b170d586 100644
--- a/x-pack/plugins/security_solution/public/common/lib/telemetry/middleware.ts
+++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/middleware.ts
@@ -8,7 +8,7 @@
import type { Action, Dispatch, MiddlewareAPI } from 'redux';
import { track, METRIC_TYPE, TELEMETRY_EVENT } from '.';
-import * as timelineActions from '../../../timelines/store/timeline/actions';
+import * as timelineActions from '../../../timelines/store/actions';
export const telemetryMiddleware = (api: MiddlewareAPI) => (next: Dispatch) => (action: Action) => {
if (timelineActions.endTimelineSaving.match(action)) {
diff --git a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts
index ba567b623ab51..732097aedbc2b 100644
--- a/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts
+++ b/x-pack/plugins/security_solution/public/common/mock/timeline_results.ts
@@ -17,8 +17,8 @@ import type { OpenTimelineResult } from '../../timelines/components/open_timelin
import type { TimelineEventsDetailsItem } from '../../../common/search_strategy';
import { Direction } from '../../../common/search_strategy';
import type { CreateTimelineProps } from '../../detections/components/alerts_table/types';
-import type { TimelineModel } from '../../timelines/store/timeline/model';
-import { timelineDefaults } from '../../timelines/store/timeline/defaults';
+import type { TimelineModel } from '../../timelines/store/model';
+import { timelineDefaults } from '../../timelines/store/defaults';
export const mockOpenTimelineQueryResults = {
totalCount: 11,
diff --git a/x-pack/plugins/security_solution/public/common/mock/utils.ts b/x-pack/plugins/security_solution/public/common/mock/utils.ts
index 3816d72e2586c..c8a1cacf2b486 100644
--- a/x-pack/plugins/security_solution/public/common/mock/utils.ts
+++ b/x-pack/plugins/security_solution/public/common/mock/utils.ts
@@ -8,7 +8,7 @@
import { hostsReducer } from '../../explore/hosts/store';
import { networkReducer } from '../../explore/network/store';
import { makeUsersReducer } from '../../explore/users/store';
-import { timelineReducer } from '../../timelines/store/timeline/reducer';
+import { timelineReducer } from '../../timelines/store/reducer';
import { managementReducer } from '../../management/store/reducer';
import type { ManagementPluginReducer } from '../../management';
import type { SubPluginsInitReducer } from '../store';
diff --git a/x-pack/plugins/security_solution/public/common/store/data_table/epic_local_storage.ts b/x-pack/plugins/security_solution/public/common/store/data_table/epic_local_storage.ts
index aea4c18e8b1fa..f84b29341b712 100644
--- a/x-pack/plugins/security_solution/public/common/store/data_table/epic_local_storage.ts
+++ b/x-pack/plugins/security_solution/public/common/store/data_table/epic_local_storage.ts
@@ -12,10 +12,10 @@ import { get } from 'lodash/fp';
import { dataTableActions } from '@kbn/securitysolution-data-table';
import type { TableIdLiteral } from '@kbn/securitysolution-data-table';
-import { updateTotalCount } from '../../../timelines/store/timeline/actions';
+import { updateTotalCount } from '../../../timelines/store/actions';
import { addTableInStorage } from '../../../timelines/containers/local_storage';
-import type { TimelineEpicDependencies } from '../../../timelines/store/timeline/types';
+import type { TimelineEpicDependencies } from '../../../timelines/store/types';
const {
applyDeltaToColumnWidth,
diff --git a/x-pack/plugins/security_solution/public/common/store/epic.ts b/x-pack/plugins/security_solution/public/common/store/epic.ts
index 7659b3542f5de..20311d6c4a163 100644
--- a/x-pack/plugins/security_solution/public/common/store/epic.ts
+++ b/x-pack/plugins/security_solution/public/common/store/epic.ts
@@ -8,16 +8,15 @@
import type { Epic } from 'redux-observable';
import { combineEpics } from 'redux-observable';
import type { Action } from 'redux';
-
import type { Observable } from 'rxjs';
import type { Storage } from '@kbn/kibana-utils-plugin/public';
import type { CoreStart } from '@kbn/core/public';
-import { createTimelineEpic } from '../../timelines/store/timeline/epic';
-import { createTimelineChangedEpic } from '../../timelines/store/timeline/epic_changed';
-import { createTimelineFavoriteEpic } from '../../timelines/store/timeline/epic_favorite';
-import { createTimelineNoteEpic } from '../../timelines/store/timeline/epic_note';
-import { createTimelinePinnedEventEpic } from '../../timelines/store/timeline/epic_pinned_event';
-import type { TimelineEpicDependencies } from '../../timelines/store/timeline/types';
+import { createTimelineEpic } from '../../timelines/store/epic';
+import { createTimelineChangedEpic } from '../../timelines/store/epic_changed';
+import { createTimelineFavoriteEpic } from '../../timelines/store/epic_favorite';
+import { createTimelineNoteEpic } from '../../timelines/store/epic_note';
+import { createTimelinePinnedEventEpic } from '../../timelines/store/epic_pinned_event';
+import type { TimelineEpicDependencies } from '../../timelines/store/types';
import { createDataTableLocalStorageEpic } from './data_table/epic_local_storage';
import { createUserAssetTableLocalStorageEpic } from '../../explore/users/store/epic_storage';
import type { State } from './types';
diff --git a/x-pack/plugins/security_solution/public/common/store/reducer.ts b/x-pack/plugins/security_solution/public/common/store/reducer.ts
index e60f801537f4b..d7b13a93caa70 100644
--- a/x-pack/plugins/security_solution/public/common/store/reducer.ts
+++ b/x-pack/plugins/security_solution/public/common/store/reducer.ts
@@ -19,7 +19,7 @@ import { sourcererReducer, sourcererModel } from './sourcerer';
import type { HostsPluginReducer } from '../../explore/hosts/store';
import type { NetworkPluginReducer } from '../../explore/network/store';
import type { UsersPluginReducer } from '../../explore/users/store';
-import type { TimelinePluginReducer } from '../../timelines/store/timeline';
+import type { TimelinePluginReducer } from '../../timelines/store';
import type { SecuritySubPlugins } from '../../app/types';
import type { ManagementPluginReducer } from '../../management';
diff --git a/x-pack/plugins/security_solution/public/common/store/store.ts b/x-pack/plugins/security_solution/public/common/store/store.ts
index cf53e2f795ead..b9f29867a32b5 100644
--- a/x-pack/plugins/security_solution/public/common/store/store.ts
+++ b/x-pack/plugins/security_solution/public/common/store/store.ts
@@ -35,9 +35,9 @@ import {
} from '../../../common/constants';
import { telemetryMiddleware } from '../lib/telemetry';
import { appSelectors } from './app';
-import { timelineSelectors } from '../../timelines/store/timeline';
-import * as timelineActions from '../../timelines/store/timeline/actions';
-import type { TimelineModel } from '../../timelines/store/timeline/model';
+import { timelineSelectors } from '../../timelines/store';
+import * as timelineActions from '../../timelines/store/actions';
+import type { TimelineModel } from '../../timelines/store/model';
import { inputsSelectors } from './inputs';
import type { SubPluginsInitReducer } from './reducer';
import { createInitialState, createReducer } from './reducer';
@@ -45,7 +45,7 @@ import { createRootEpic } from './epic';
import type { AppAction } from './actions';
import type { Immutable } from '../../../common/endpoint/types';
import type { State } from './types';
-import type { TimelineEpicDependencies, TimelineState } from '../../timelines/store/timeline/types';
+import type { TimelineEpicDependencies, TimelineState } from '../../timelines/store/types';
import type { KibanaDataView, SourcererModel, SourcererDataView } from './sourcerer/model';
import { initDataView } from './sourcerer/model';
import type { AppObservableLibs, StartedSubPlugins, StartPlugins } from '../../types';
diff --git a/x-pack/plugins/security_solution/public/common/store/types.ts b/x-pack/plugins/security_solution/public/common/store/types.ts
index ec41cdda85ef2..359a65d4fb122 100644
--- a/x-pack/plugins/security_solution/public/common/store/types.ts
+++ b/x-pack/plugins/security_solution/public/common/store/types.ts
@@ -17,7 +17,7 @@ import type { InputsState } from './inputs/reducer';
import type { SourcererState } from './sourcerer/reducer';
import type { HostsPluginState } from '../../explore/hosts/store';
import type { DragAndDropState } from './drag_and_drop/reducer';
-import type { TimelinePluginState } from '../../timelines/store/timeline';
+import type { TimelinePluginState } from '../../timelines/store';
import type { NetworkPluginState } from '../../explore/network/store';
import type { ManagementPluginState } from '../../management';
import type { UsersPluginState } from '../../explore/users/store';
diff --git a/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx b/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx
index 2b0bb060d7d9b..dca72a31414ba 100644
--- a/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx
+++ b/x-pack/plugins/security_solution/public/common/utils/timeline/use_timeline_click.tsx
@@ -12,7 +12,7 @@ import {
queryTimelineById,
} from '../../../timelines/components/open_timeline/helpers';
import type { TimelineErrorCallback } from '../../../timelines/components/open_timeline/types';
-import { updateIsLoading as dispatchUpdateIsLoading } from '../../../timelines/store/timeline/actions';
+import { updateIsLoading as dispatchUpdateIsLoading } from '../../../timelines/store/actions';
export const useTimelineClick = () => {
const dispatch = useDispatch();
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx
index 6f7521c3c1d60..ea44819dae5ea 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx
@@ -57,7 +57,7 @@ import {
USER,
} from '@kbn/lists-plugin/common/constants.mock';
import { of } from 'rxjs';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
jest.mock('../../../timelines/containers/api', () => ({
getTimelineTemplate: jest.fn(),
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx
index 364b521c1ec30..a9a84eb0231a2 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.tsx
@@ -58,7 +58,7 @@ import type {
TimelineEventsDetailsStrategyResponse,
} from '../../../../common/search_strategy/timeline';
import { TimelineEventsQueries } from '../../../../common/search_strategy/timeline';
-import { timelineDefaults } from '../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../timelines/store/defaults';
import {
omitTypenameInTimeline,
formatTimelineResultToModel,
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx
index 304049fff9a72..e1841709c17ba 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline.tsx
@@ -22,7 +22,7 @@ import { useTimelineEventsHandler } from '../../../../timelines/containers';
import { eventsViewerSelector } from '../../../../common/components/events_viewer/selectors';
import type { State } from '../../../../common/store/types';
import { dispatchUpdateTimeline } from '../../../../timelines/components/open_timeline/helpers';
-import { timelineActions } from '../../../../timelines/store/timeline';
+import { timelineActions } from '../../../../timelines/store';
import { useCreateTimeline } from '../../../../timelines/components/timeline/properties/use_create_timeline';
import { INVESTIGATE_BULK_IN_TIMELINE } from '../translations';
import { TimelineId } from '../../../../../common/types/timeline';
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx
index 02d149860c1b4..8adcf707c98dd 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx
@@ -19,11 +19,11 @@ import { useApi } from '@kbn/securitysolution-list-hooks';
import type { Filter } from '@kbn/es-query';
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
import { createHistoryEntry } from '../../../../common/utils/global_query_string/helpers';
-import { timelineDefaults } from '../../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../../timelines/store/defaults';
import { useKibana } from '../../../../common/lib/kibana';
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineType } from '../../../../../common/api/timeline';
-import { timelineActions, timelineSelectors } from '../../../../timelines/store/timeline';
+import { timelineActions, timelineSelectors } from '../../../../timelines/store';
import { sendAlertToTimelineAction } from '../actions';
import { dispatchUpdateTimeline } from '../../../../timelines/components/open_timeline/helpers';
import { useCreateTimeline } from '../../../../timelines/components/timeline/properties/use_create_timeline';
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/types.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/types.ts
index b226ad81b9771..55616b5aefc29 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/types.ts
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/types.ts
@@ -12,7 +12,7 @@ import type { EuiContextMenuPanelItemDescriptorEntry } from '@elastic/eui/src/co
import type { Status } from '../../../../common/api/detection_engine';
import type { Note } from '../../../../common/api/timeline';
import type { DataProvider } from '../../../timelines/components/timeline/data_providers/data_provider';
-import type { TimelineModel } from '../../../timelines/store/timeline/model';
+import type { TimelineModel } from '../../../timelines/store/model';
import type { inputsModel } from '../../../common/store';
export interface SetEventsLoadingProps {
diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx
index c68194187e4b7..0a293955d0f78 100644
--- a/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/rules/query_bar/index.tsx
@@ -18,7 +18,7 @@ import { OpenTimelineModal } from '../../../../timelines/components/open_timelin
import type { ActionTimelineToShow } from '../../../../timelines/components/open_timeline/types';
import { QueryBar } from '../../../../common/components/query_bar';
import { useKibana } from '../../../../common/lib/kibana';
-import type { TimelineModel } from '../../../../timelines/store/timeline/model';
+import type { TimelineModel } from '../../../../timelines/store/model';
import { useSavedQueryServices } from '../../../../common/utils/saved_query_services';
import type { FieldHook } from '../../../../shared_imports';
import { getFieldValidityAndErrorMessage } from '../../../../shared_imports';
diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx
index 4818a8c8f1acd..c5b2036efd701 100644
--- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx
@@ -11,7 +11,7 @@ import { useDispatch } from 'react-redux';
import { i18n } from '@kbn/i18n';
import type { EqlOptionsSelected } from '@kbn/timelines-plugin/common';
import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery';
-import { updateIsLoading } from '../../../../timelines/store/timeline/actions';
+import { updateIsLoading } from '../../../../timelines/store/actions';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import type { TimelineModel } from '../../../..';
diff --git a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx
index 2e5fc3b3dbbab..28e432a126a28 100644
--- a/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx
+++ b/x-pack/plugins/security_solution/public/explore/users/pages/details/index.tsx
@@ -44,7 +44,7 @@ import type { UsersDetailsProps } from './types';
import { getUsersDetailsPageFilters } from './helpers';
import { showGlobalFilters } from '../../../../timelines/components/timeline/helpers';
import { useGlobalFullScreen } from '../../../../common/containers/use_full_screen';
-import { timelineDefaults } from '../../../../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../../../../timelines/store/defaults';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import {
useDeepEqualSelector,
diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx
index e0500a1847cce..40c3b513114e7 100644
--- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx
+++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx
@@ -14,7 +14,7 @@ import { useStartTransaction } from '../../../../common/lib/apm/use_start_transa
import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline';
import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions';
import { getScopedActions } from '../../../../helpers';
-import { setActiveTabTimeline } from '../../../../timelines/store/timeline/actions';
+import { setActiveTabTimeline } from '../../../../timelines/store/actions';
import { useRightPanelContext } from '../context';
import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver';
import { AnalyzerPreview } from './analyzer_preview';
diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx
index d0214b725a44e..5b5f964a8fdc0 100644
--- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx
+++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx
@@ -20,7 +20,7 @@ import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions';
import { ExpandablePanel } from '../../../shared/components/expandable_panel';
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 { setActiveTabTimeline } from '../../../../timelines/store/actions';
import { getScopedActions } from '../../../../helpers';
const timelineId = 'timeline-1';
diff --git a/x-pack/plugins/security_solution/public/helpers.tsx b/x-pack/plugins/security_solution/public/helpers.tsx
index b245a6ae2f6bc..09ad6612bdb06 100644
--- a/x-pack/plugins/security_solution/public/helpers.tsx
+++ b/x-pack/plugins/security_solution/public/helpers.tsx
@@ -36,7 +36,7 @@ import { NoPrivilegesPage } from './common/components/no_privileges';
import { SecurityPageName } from './app/types';
import type { InspectResponse, StartedSubPlugins, StartServices } from './types';
import { CASES_SUB_PLUGIN_KEY } from './types';
-import { timelineActions } from './timelines/store/timeline';
+import { timelineActions } from './timelines/store';
import { TimelineId } from '../common/types';
import { SourcererScopeName } from './common/store/sourcerer/model';
diff --git a/x-pack/plugins/security_solution/public/index.ts b/x-pack/plugins/security_solution/public/index.ts
index 3af2b724b014e..92fcf14ace691 100644
--- a/x-pack/plugins/security_solution/public/index.ts
+++ b/x-pack/plugins/security_solution/public/index.ts
@@ -8,7 +8,7 @@ import type { PluginInitializerContext } from '@kbn/core/public';
import { Plugin } from './plugin';
import type { PluginSetup, PluginStart } from './types';
-export type { TimelineModel } from './timelines/store/timeline/model';
+export type { TimelineModel } from './timelines/store/model';
export type { LinkItem } from './common/links';
export type { FetchRulesResponse } from './detection_engine/rule_management/logic/types';
diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.test.ts b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.test.ts
index 5e451f6c44cc8..1257e1e480298 100644
--- a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.test.ts
+++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.test.ts
@@ -8,7 +8,7 @@
import { renderHook } from '@testing-library/react-hooks';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
-import { updateProviders } from '../../../../timelines/store/timeline/actions';
+import { updateProviders } from '../../../../timelines/store/actions';
import { useNavigateToTimeline } from './use_navigate_to_timeline';
import * as mock from './mock_data';
diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx
index 762286e2177fc..40ac8b91cfd84 100644
--- a/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/hooks/use_navigate_to_timeline.tsx
@@ -20,7 +20,7 @@ import type { DataProvider, QueryOperator } from '../../../../../common/types/ti
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineType } from '../../../../../common/api/timeline';
import { useCreateTimeline } from '../../../../timelines/components/timeline/properties/use_create_timeline';
-import { updateProviders } from '../../../../timelines/store/timeline/actions';
+import { updateProviders } from '../../../../timelines/store/actions';
import { sourcererSelectors } from '../../../../common/store';
import type { TimeRange } from '../../../../common/store/inputs/model';
diff --git a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx
index e6c8068c0a865..0e5b4d6903068 100644
--- a/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/recent_timelines/index.tsx
@@ -16,7 +16,7 @@ import {
dispatchUpdateTimeline,
} from '../../../timelines/components/open_timeline/helpers';
import type { OnOpenTimeline } from '../../../timelines/components/open_timeline/types';
-import { updateIsLoading as dispatchUpdateIsLoading } from '../../../timelines/store/timeline/actions';
+import { updateIsLoading as dispatchUpdateIsLoading } from '../../../timelines/store/actions';
import { RecentTimelines } from './recent_timelines';
import * as i18n from './translations';
diff --git a/x-pack/plugins/security_solution/public/threat_intelligence/use_investigate_in_timeline.ts b/x-pack/plugins/security_solution/public/threat_intelligence/use_investigate_in_timeline.ts
index 69d626f05de91..c73855cf7d115 100644
--- a/x-pack/plugins/security_solution/public/threat_intelligence/use_investigate_in_timeline.ts
+++ b/x-pack/plugins/security_solution/public/threat_intelligence/use_investigate_in_timeline.ts
@@ -7,7 +7,7 @@
import { useCallback, useMemo } from 'react';
import { useDispatch } from 'react-redux';
-import { timelineDefaults } from '../timelines/store/timeline/defaults';
+import { timelineDefaults } from '../timelines/store/defaults';
import { APP_UI_ID } from '../../common/constants';
import type { DataProvider } from '../../common/types';
import { TimelineId } from '../../common/types/timeline';
@@ -15,7 +15,7 @@ import { TimelineType } from '../../common/api/timeline';
import { useDeepEqualSelector } from '../common/hooks/use_selector';
import { useKibana } from '../common/lib/kibana';
import { useStartTransaction } from '../common/lib/apm/use_start_transaction';
-import { timelineActions, timelineSelectors } from '../timelines/store/timeline';
+import { timelineActions, timelineSelectors } from '../timelines/store';
import { useCreateTimeline } from '../timelines/components/timeline/properties/use_create_timeline';
import type { CreateTimelineProps } from '../detections/components/alerts_table/types';
import { dispatchUpdateTimeline } from '../timelines/components/open_timeline/helpers';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx
index 10154901f2db7..8028eb92eac7b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/action_menu/save_timeline_modal.tsx
@@ -27,7 +27,7 @@ import { getUseField, Field, Form, useForm } from '../../../../shared_imports';
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import * as commonI18n from '../../timeline/properties/translations';
import * as i18n from './translations';
import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx
index 81e520368da6c..4eb701c5a8d98 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/add_to_case_button/index.tsx
@@ -12,15 +12,15 @@ import { useDispatch } from 'react-redux';
import type { CaseUI } from '@kbn/cases-plugin/common';
import { APP_ID, APP_UI_ID } from '../../../../../common/constants';
-import { timelineSelectors } from '../../../store/timeline';
-import { setInsertTimeline, showTimeline } from '../../../store/timeline/actions';
+import { timelineSelectors } from '../../../store';
+import { setInsertTimeline, showTimeline } from '../../../store/actions';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { useKibana } from '../../../../common/lib/kibana';
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline';
import { getCreateCaseUrl, getCaseDetailsUrl } from '../../../../common/components/link_to';
import { SecurityPageName } from '../../../../app/types';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import * as i18n from '../../timeline/properties/translations';
interface Props {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx
index cbc38f4ccecb9..9a863a5fe8184 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/active_timelines.tsx
@@ -18,7 +18,7 @@ import {
focusActiveTimelineButton,
} from '../../timeline/helpers';
import { UNTITLED_TIMELINE, UNTITLED_TEMPLATE } from '../../timeline/properties/translations';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import * as i18n from './translations';
export interface ActiveTimelinesProps {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx
index b6e4d354e9c6f..cba27263d8dfe 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/index.tsx
@@ -15,7 +15,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { createHistoryEntry } from '../../../../common/utils/global_query_string/helpers';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import type { State } from '../../../../common/store';
import { useKibana } from '../../../../common/lib/kibana';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
@@ -27,7 +27,7 @@ import * as i18n from './translations';
import { TimelineActionMenu } from '../action_menu';
import { AddToFavoritesButton } from '../../timeline/properties/helpers';
import { TimelineStatusInfo } from './timeline_status_info';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { AddTimelineButton } from '../add_timeline_button';
interface FlyoutHeaderPanelProps {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/selectors.ts
index 494489a1c7bfe..441ae5fed1a7e 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/header/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/header/selectors.ts
@@ -8,7 +8,7 @@
import { createSelector } from 'reselect';
import { TimelineStatus } from '../../../../../common/api/timeline';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
export const getTimelineStatusByIdSelector = () =>
createSelector(timelineSelectors.selectTimeline, (timeline) => ({
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.test.tsx
index 5d0e7eebc5eef..73454f6b54b6b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.test.tsx
@@ -12,7 +12,7 @@ import '../../../common/mock/react_beautiful_dnd';
import { TestProviders } from '../../../common/mock';
import { TimelineId } from '../../../../common/types/timeline';
-import * as timelineActions from '../../store/timeline/actions';
+import * as timelineActions from '../../store/actions';
import { Flyout } from '.';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx
index 2f9ff64c20970..13514d82cbe7f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx
@@ -16,7 +16,7 @@ import { FlyoutBottomBar } from './bottom_bar';
import { Pane } from './pane';
import { getTimelineShowStatusByIdSelector } from './selectors';
import { useTimelineSavePrompt } from '../../../common/hooks/timeline/use_timeline_save_prompt';
-import { timelineActions } from '../../store/timeline';
+import { timelineActions } from '../../store';
import { focusActiveTimelineButton } from '../timeline/helpers';
interface OwnProps {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts
index df631c75a97d1..b02284aec6555 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/selectors.ts
@@ -9,7 +9,7 @@ import { createSelector } from 'reselect';
import { TimelineTabs } from '../../../../common/types/timeline';
import { TimelineStatus } from '../../../../common/api/timeline';
-import { timelineSelectors } from '../../store/timeline';
+import { timelineSelectors } from '../../store';
export const getTimelineShowStatusByIdSelector = () =>
createSelector(timelineSelectors.selectTimeline, (timeline) => ({
diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx
index b44fb4afc04ee..b7e0c782a9e6e 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx
@@ -11,7 +11,7 @@ import userEvent from '@testing-library/user-event';
import { FormattedIp } from '.';
import { TestProviders } from '../../../common/mock';
import { TimelineId, TimelineTabs } from '../../../../common/types/timeline';
-import { timelineActions } from '../../store/timeline';
+import { timelineActions } from '../../store';
import { activeTimeline } from '../../containers/active_timeline_context';
import { StatefulEventContext } from '../../../common/components/events_viewer/stateful_event_context';
@@ -44,8 +44,8 @@ jest.mock('../../../common/components/drag_and_drop/draggable_wrapper', () => {
};
});
-jest.mock('../../store/timeline', () => {
- const original = jest.requireActual('../../store/timeline');
+jest.mock('../../store', () => {
+ const original = jest.requireActual('../../store');
return {
...original,
timelineActions: {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx
index 7b686f1bbc113..75c074c517758 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx
@@ -33,8 +33,8 @@ import { isFullScreen } from '../timeline/body/column_headers';
import { inputsActions } from '../../../common/store/actions';
import { Resolver } from '../../../resolver/view';
import { useTimelineDataFilters } from '../../containers/use_timeline_data_filters';
-import { timelineSelectors } from '../../store/timeline';
-import { timelineDefaults } from '../../store/timeline/defaults';
+import { timelineSelectors } from '../../store';
+import { timelineDefaults } from '../../store/defaults';
const SESSION_VIEW_FULL_SCREEN = 'sessionViewFullScreen';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts
index 6bd865e2750a2..7d789dbc46623 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts
@@ -13,13 +13,13 @@ import {
mockTimelineModel,
mockGetOneTimelineResult,
} from '../../../common/mock';
-import { timelineDefaults } from '../../store/timeline/defaults';
+import { timelineDefaults } from '../../store/defaults';
import { setTimelineRangeDatePicker as dispatchSetTimelineRangeDatePicker } from '../../../common/store/inputs/actions';
import {
applyKqlFilterQuery as dispatchApplyKqlFilterQuery,
addTimeline as dispatchAddTimeline,
addNote as dispatchAddGlobalTimelineNote,
-} from '../../store/timeline/actions';
+} from '../../store/actions';
import {
addNotes as dispatchAddNotes,
updateNote as dispatchUpdateNote,
@@ -50,7 +50,7 @@ import { resolveTimeline } from '../../containers/api';
jest.mock('../../../common/store/inputs/actions');
jest.mock('../../../common/utils/normalize_time_range');
-jest.mock('../../store/timeline/actions');
+jest.mock('../../store/actions');
jest.mock('../../../common/store/app/actions');
jest.mock('uuid', () => {
return {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts
index e4f5f8746cc0c..f7468d4958f04 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts
@@ -38,9 +38,9 @@ import {
applyKqlFilterQuery as dispatchApplyKqlFilterQuery,
addTimeline as dispatchAddTimeline,
addNote as dispatchAddGlobalTimelineNote,
-} from '../../store/timeline/actions';
-import type { TimelineModel } from '../../store/timeline/model';
-import { timelineDefaults } from '../../store/timeline/defaults';
+} from '../../store/actions';
+import type { TimelineModel } from '../../store/model';
+import { timelineDefaults } from '../../store/defaults';
import {
defaultColumnHeaderType,
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx
index 60f4dab89a2c1..dc2cca5104497 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx
@@ -18,12 +18,12 @@ import { SecurityPageName } from '../../../../common/constants';
import { useShallowEqualSelector } from '../../../common/hooks/use_selector';
import type { SortFieldTimeline } from '../../../../common/api/timeline';
import { TimelineId } from '../../../../common/types/timeline';
-import type { TimelineModel } from '../../store/timeline/model';
-import { timelineSelectors } from '../../store/timeline';
+import type { TimelineModel } from '../../store/model';
+import { timelineSelectors } from '../../store';
import {
createTimeline as dispatchCreateNewTimeline,
updateIsLoading as dispatchUpdateIsLoading,
-} from '../../store/timeline/actions';
+} from '../../store/actions';
import { useGetAllTimeline } from '../../containers/all';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx
index 92011428edf0d..caff8fee65b2f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx
@@ -24,7 +24,7 @@ import { useMutation } from '@tanstack/react-query';
import type { TimelineResultNote } from '../types';
import { getEmptyValue, defaultToEmptyTag } from '../../../../common/components/empty_value';
import { MarkdownRenderer } from '../../../../common/components/markdown_editor';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import { appActions } from '../../../../common/store/app';
import { NOTE_CONTENT_CLASS_NAME } from '../../timeline/body/helpers';
import * as i18n from './translations';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx
index 9d803357058a0..75990ce7792d0 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.tsx
@@ -8,7 +8,7 @@
import { EuiModal } from '@elastic/eui';
import React from 'react';
-import type { TimelineModel } from '../../../store/timeline/model';
+import type { TimelineModel } from '../../../store/model';
import * as i18n from '../translations';
import type { ActionTimelineToShow } from '../types';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts
index 4a300c2c02ca1..e5a8abc612b8e 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/types.ts
@@ -7,7 +7,7 @@
import type React from 'react';
import type { AllTimelinesVariables } from '../../containers/all';
-import type { TimelineModel } from '../../store/timeline/model';
+import type { TimelineModel } from '../../store/model';
import type {
RowRendererId,
SingleTimelineResolveResponse,
diff --git a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx
index 05b1e7254b9dd..be33b84ca5f0c 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/row_renderers_browser/index.tsx
@@ -25,9 +25,9 @@ import styled from 'styled-components';
import type { State } from '../../../common/store';
import { RowRendererId } from '../../../../common/api/timeline';
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
-import { setExcludedRowRendererIds as dispatchSetExcludedRowRendererIds } from '../../store/timeline/actions';
-import { timelineSelectors } from '../../store/timeline';
-import { timelineDefaults } from '../../store/timeline/defaults';
+import { setExcludedRowRendererIds as dispatchSetExcludedRowRendererIds } from '../../store/actions';
+import { timelineSelectors } from '../../store';
+import { timelineDefaults } from '../../store/defaults';
import { RowRenderersBrowser } from './row_renderers_browser';
import * as i18n from './translations';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.test.tsx
index 1d82612e4b2aa..a217cd0baea47 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.test.tsx
@@ -7,7 +7,7 @@
import { renderHook, act } from '@testing-library/react-hooks';
import type { UseDetailPanelConfig } from './use_detail_panel';
import { useDetailPanel } from './use_detail_panel';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline';
@@ -16,7 +16,7 @@ import { FlowTargetSourceDest } from '../../../../../common/search_strategy';
const mockDispatch = jest.fn();
jest.mock('../../../../common/lib/kibana');
jest.mock('../../../../common/hooks/use_selector');
-jest.mock('../../../store/timeline');
+jest.mock('../../../store');
jest.mock('react-redux', () => {
const original = jest.requireActual('react-redux');
return {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx
index 5cde89c82e796..45f85294bfa37 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/hooks/use_detail_panel.tsx
@@ -12,12 +12,12 @@ import { dataTableSelectors } from '@kbn/securitysolution-data-table';
import type { ExpandedDetailType } from '../../../../../common/types';
import { getScopedActions, isInTableScope, isTimelineScope } from '../../../../helpers';
import type { FlowTargetSourceDest } from '../../../../../common/search_strategy';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import type { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { activeTimeline } from '../../../containers/active_timeline_context';
import { TimelineTabs, TimelineId } from '../../../../../common/types/timeline';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { DetailsPanel as DetailsPanelComponent } from '..';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx
index ad33fdfe1b73e..ae2cd149ef69d 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/index.tsx
@@ -13,8 +13,8 @@ import { EuiFlyout } from '@elastic/eui';
import type { EntityType } from '@kbn/timelines-plugin/common';
import { dataTableActions, dataTableSelectors } from '@kbn/securitysolution-data-table';
import { getScopedActions, isInTableScope, isTimelineScope } from '../../../helpers';
-import { timelineSelectors } from '../../store/timeline';
-import { timelineDefaults } from '../../store/timeline/defaults';
+import { timelineSelectors } from '../../store';
+import { timelineDefaults } from '../../store/defaults';
import type { BrowserFields } from '../../../common/containers/source';
import type { RunTimeMappings } from '../../../common/store/sourcerer/model';
import { TimelineId, TimelineTabs } from '../../../../common/types/timeline';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx
index 945c999dbe639..635f1a91a795d 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx
@@ -27,7 +27,7 @@ import { EventsTh, EventsThContent, EventsHeadingHandle } from '../../styles';
import type { Sort } from '../sort';
import { Header } from './header';
-import { timelineActions } from '../../../../store/timeline';
+import { timelineActions } from '../../../../store';
import * as i18n from './translations';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx
index 3f92df6827681..d80831d49abcc 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx
@@ -8,7 +8,7 @@
import { mount, shallow } from 'enzyme';
import React from 'react';
-import { timelineActions } from '../../../../../store/timeline';
+import { timelineActions } from '../../../../../store';
import { TestProviders } from '../../../../../../common/mock';
import type { Sort } from '../../sort';
import { CloseButton } from '../actions';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx
index 142d6f7894c22..99c11571f0c2d 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx
@@ -15,7 +15,7 @@ import {
useDeepEqualSelector,
useShallowEqualSelector,
} from '../../../../../../common/hooks/use_selector';
-import { timelineActions, timelineSelectors } from '../../../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../../../store';
import type { OnFilterChange } from '../../../events';
import type { Sort } from '../../sort';
import { Actions } from '../actions';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx
index 52aae6ff69a59..cac232fd6ea34 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx
@@ -7,7 +7,7 @@
import { createSelector } from 'reselect';
import { TimelineTabs } from '../../../../../../../common/types/timeline';
-import { selectTimeline } from '../../../../../store/timeline/selectors';
+import { selectTimeline } from '../../../../../store/selectors';
export const isEqlOnSelector = () =>
createSelector(selectTimeline, (timeline) => timeline?.activeTab === TimelineTabs.eql);
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx
index b1f7ded5d5c3d..4042619404d27 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx
@@ -18,7 +18,7 @@ import { useMountAppended } from '../../../../../common/utils/use_mount_appended
import type { ColumnHeadersComponentProps } from '.';
import { ColumnHeadersComponent } from '.';
import { cloneDeep } from 'lodash/fp';
-import { timelineActions } from '../../../../store/timeline';
+import { timelineActions } from '../../../../store';
import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline';
import { Direction } from '../../../../../../common/search_strategy';
import { getDefaultControlColumn } from '../control_columns';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx
index 37ac268073bcc..dbf5cf8e94ff6 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx
@@ -11,7 +11,7 @@ import { Droppable } from '@hello-pangea/dnd';
import { useDispatch } from 'react-redux';
import type { ControlColumnProps, HeaderActionProps } from '../../../../../../common/types';
-import { removeColumn, upsertColumn } from '../../../../store/timeline/actions';
+import { removeColumn, upsertColumn } from '../../../../store/actions';
import { DragEffects } from '../../../../../common/components/drag_and_drop/draggable_wrapper';
import { DraggableFieldBadge } from '../../../../../common/components/draggables/field_badge';
import type { BrowserFields } from '../../../../../common/containers/source';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx
index 42c34a5f06e0e..8faab92f5747f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx
@@ -29,13 +29,13 @@ import { useEventDetailsWidthContext } from '../../../../../common/components/ev
import { EventColumnView } from './event_column_view';
import type { inputsModel } from '../../../../../common/store';
import { appSelectors } from '../../../../../common/store';
-import { timelineActions, timelineSelectors } from '../../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../../store';
import { activeTimeline } from '../../../../containers/active_timeline_context';
import type { TimelineResultNote } from '../../../open_timeline/types';
import { getRowRenderer } from '../renderers/get_row_renderer';
import { StatefulRowRenderer } from './stateful_row_renderer';
import { NOTES_BUTTON_CLASS_NAME } from '../../properties/helpers';
-import { timelineDefaults } from '../../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../../store/defaults';
import { useGetMappedNonEcsValue } from '../data_driven_columns';
import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context';
import type {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx
index 4ab99faba09c4..2cd9587a63de5 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx
@@ -31,7 +31,7 @@ import type { Props } from '.';
import { StatefulBody } from '.';
import type { Sort } from './sort';
import { getDefaultControlColumn } from './control_columns';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline';
import { defaultRowRenderers } from './renderers';
import type { State } from '../../../../common/store';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx
index ac5d73fb7e085..0478b1cf90ad5 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx
@@ -24,8 +24,8 @@ import { RowRendererId } from '../../../../../common/api/timeline';
import type { BrowserFields } from '../../../../common/containers/source';
import type { TimelineItem } from '../../../../../common/search_strategy/timeline';
import type { inputsModel, State } from '../../../../common/store';
-import { timelineDefaults } from '../../../store/timeline/defaults';
-import { timelineActions } from '../../../store/timeline';
+import { timelineDefaults } from '../../../store/defaults';
+import { timelineActions } from '../../../store';
import type { OnRowSelected, OnSelectAll } from '../events';
import { getColumnHeaders } from './column_headers/helpers';
import { getEventIdToDataMapping } from './helpers';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx
index 63a254f4d2d6f..1535b05a97a4f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx
@@ -11,7 +11,7 @@ import { waitFor } from '@testing-library/react';
import { HostName } from './host_name';
import { TestProviders } from '../../../../../common/mock';
import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline';
-import { timelineActions } from '../../../../store/timeline';
+import { timelineActions } from '../../../../store';
import { activeTimeline } from '../../../../containers/active_timeline_context';
import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context';
import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock';
@@ -44,8 +44,8 @@ jest.mock('../../../../../common/components/draggables', () => ({
DefaultDraggable: () => ,
}));
-jest.mock('../../../../store/timeline', () => {
- const original = jest.requireActual('../../../../store/timeline');
+jest.mock('../../../../store', () => {
+ const original = jest.requireActual('../../../../store');
return {
...original,
timelineActions: {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx
index a2183ec19c939..81ab0e35ee213 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx
@@ -10,7 +10,7 @@ import { waitFor } from '@testing-library/react';
import { TestProviders } from '../../../../../common/mock';
import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline';
-import { timelineActions } from '../../../../store/timeline';
+import { timelineActions } from '../../../../store';
import { activeTimeline } from '../../../../containers/active_timeline_context';
import { UserName } from './user_name';
import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context';
@@ -44,8 +44,8 @@ jest.mock('../../../../../common/components/draggables', () => ({
DefaultDraggable: () => ,
}));
-jest.mock('../../../../store/timeline', () => {
- const original = jest.requireActual('../../../../store/timeline');
+jest.mock('../../../../store', () => {
+ const original = jest.requireActual('../../../../store');
return {
...original,
timelineActions: {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/selectors/index.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/selectors/index.ts
index e4c1f422886fa..26e2b11bd2b4b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/selectors/index.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/selectors/index.ts
@@ -7,7 +7,7 @@
import { createSelector } from 'reselect';
-import { getTimelineByIdSelector } from '../../../../store/timeline/selectors';
+import { getTimelineByIdSelector } from '../../../../store/selectors';
/**
* This selector combines all the selectors used by the Timeline `StatefulBody`,
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/add_data_provider_popover.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/add_data_provider_popover.tsx
index bff85fdf28e46..5903d4bfe3022 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/add_data_provider_popover.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/add_data_provider_popover.tsx
@@ -26,7 +26,7 @@ import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { StatefulEditDataProvider } from '../../edit_data_provider';
import { addContentToTimeline, getDisplayValue } from './helpers';
import { DataProviderType } from './data_provider';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
import { ADD_FIELD_LABEL, ADD_TEMPLATE_FIELD_LABEL } from './translations';
interface AddDataProviderPopoverProps {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/helpers.tsx
index d96e98212f38d..53ac22d384a04 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/helpers.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/helpers.tsx
@@ -9,7 +9,7 @@ import { omit } from 'lodash/fp';
import type { DraggableLocation } from '@hello-pangea/dnd';
import type { Dispatch } from 'redux';
-import { updateProviders } from '../../../store/timeline/actions';
+import { updateProviders } from '../../../store/actions';
import type { PrimitiveOrArrayOfPrimitives } from '../../../../common/lib/kuery';
import { isPrimitiveArray } from '../helpers';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx
index c712c1b5c8df5..175283e418246 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/index.tsx
@@ -21,13 +21,13 @@ import { droppableTimelineProvidersPrefix } from '../../../../common/components/
import { Empty } from './empty';
import { Providers } from './providers';
-import { timelineSelectors } from '../../../store/timeline';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineSelectors } from '../../../store';
+import { timelineDefaults } from '../../../store/defaults';
import * as i18n from './translations';
import { options } from '../search_or_filter/helpers';
-import type { KqlMode } from '../../../store/timeline/model';
-import { updateKqlMode } from '../../../store/timeline/actions';
+import type { KqlMode } from '../../../store/model';
+import { updateKqlMode } from '../../../store/actions';
interface Props {
timelineId: string;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx
index b40b15a331fa0..871a82a9beb29 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx
@@ -15,7 +15,7 @@ import {
useDeepEqualSelector,
useShallowEqualSelector,
} from '../../../../common/hooks/use_selector';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
import type { PrimitiveOrArrayOfPrimitives } from '../../../../common/lib/kuery';
import type { OnDataProviderEdited } from '../events';
@@ -24,7 +24,7 @@ import { ProviderItemActions } from './provider_item_actions';
import type { DataProvidersAnd, QueryOperator } from './data_provider';
import { DataProviderType } from './data_provider';
import { dragAndDropActions } from '../../../../common/store/drag_and_drop';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
interface ProviderItemBadgeProps {
andProviderId?: string;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx
index a0be505921850..d6492c0d864b0 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.test.tsx
@@ -11,7 +11,7 @@ import React from 'react';
import { TestProviders } from '../../../../common/mock/test_providers';
import { DroppableWrapper } from '../../../../common/components/drag_and_drop/droppable_wrapper';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { mockDataProviders } from './mock/mock_data_providers';
import { Providers } from './providers';
import { DELETE_CLASS_NAME, ENABLE_CLASS_NAME, EXCLUDE_CLASS_NAME } from './provider_item_actions';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx
index 5d581a505742f..dd7eb5cf11051 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/providers.tsx
@@ -18,7 +18,7 @@ import {
IS_DRAGGING_CLASS_NAME,
} from '@kbn/securitysolution-t-grid';
import { useDraggableKeyboardWrapper } from '../../../../common/components/drag_and_drop/draggable_keyboard_wrapper_hook';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { AndOrBadge } from '../../../../common/components/and_or_badge';
import { AddDataProviderPopover } from './add_data_provider_popover';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx
index 63d20993174d6..f6d5465ab492c 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.tsx
@@ -24,7 +24,7 @@ import { InPortal } from 'react-reverse-portal';
import type { ControlColumnProps } from '../../../../../common/types';
import { InputsModelId } from '../../../../common/store/inputs/constants';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import type { CellValueElementProps } from '../cell_rendering';
import type { TimelineItem } from '../../../../../common/search_strategy';
import { useTimelineEvents } from '../../../containers';
@@ -42,10 +42,10 @@ import { EventDetailsWidthProvider } from '../../../../common/components/events_
import type { inputsModel, State } from '../../../../common/store';
import { inputsSelectors } from '../../../../common/store';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { useEqlEventsCountPortal } from '../../../../common/hooks/use_timeline_events_count';
-import type { TimelineModel } from '../../../store/timeline/model';
+import type { TimelineModel } from '../../../store/model';
import { TimelineDatePickerLock } from '../date_picker_lock';
import { useTimelineFullScreen } from '../../../../common/containers/use_full_screen';
import { activeTimeline } from '../../../containers/active_timeline_context';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/index.tsx
index c5762e0f0a45d..e8a2a2cbc9efb 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/esql_tab_content/index.tsx
@@ -25,11 +25,11 @@ import { useDiscoverState } from './use_discover_state';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { useSetDiscoverCustomizationCallbacks } from './customizations/use_set_discover_customizations';
import { EmbeddedDiscoverContainer } from './styles';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
import { useShallowEqualSelector } from '../../../../common/hooks/use_selector';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { savedSearchComparator } from './utils';
-import { setIsDiscoverSavedSearchLoaded } from '../../../store/timeline/actions';
+import { setIsDiscoverSavedSearchLoaded } from '../../../store/actions';
import { GET_TIMELINE_DISCOVER_SAVED_SEARCH_TITLE } from './translations';
const HideSearchSessionIndicatorBreadcrumbIcon = createGlobalStyle`
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx
index b37139f6b8406..019a4a1ce4132 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/footer/index.tsx
@@ -28,7 +28,7 @@ import { EVENTS_COUNT_BUTTON_CLASS_NAME } from '../helpers';
import * as i18n from './translations';
import { useEventDetailsWidthContext } from '../../../../common/components/events_viewer/event_details_width_context';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
import { useKibana } from '../../../../common/lib/kibana';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx
index 85c68e823da1b..844dbc3712e59 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/graph_tab_content/index.tsx
@@ -8,7 +8,7 @@
import React, { useMemo } from 'react';
import { EuiFlexItem } from '@elastic/eui';
import styled from 'styled-components';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
import { useShallowEqualSelector } from '../../../../common/hooks/use_selector';
import type { TimelineId } from '../../../../../common/types/timeline';
import { GraphOverlay } from '../../graph_overlay';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx
index 0ebc326a35226..f1e8b55b7233b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx
@@ -13,8 +13,8 @@ import styled from 'styled-components';
import { isTab } from '@kbn/timelines-plugin/public';
import { useUserPrivileges } from '../../../common/components/user_privileges';
-import { timelineActions, timelineSelectors } from '../../store/timeline';
-import { timelineDefaults } from '../../store/timeline/defaults';
+import { timelineActions, timelineSelectors } from '../../store';
+import { timelineDefaults } from '../../store/defaults';
import { defaultHeaders } from './body/column_headers/default_headers';
import type { CellValueElementProps } from './cell_rendering';
import { SourcererScopeName } from '../../../common/store/sourcerer/model';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx
index 31eb9ad5e5e53..c4f49c245e6d3 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/kpi/kpi_container.tsx
@@ -19,8 +19,8 @@ import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { TimelineKPIs } from './kpis';
import { useTimelineKpis } from '../../../containers/kpis';
import { useKibana } from '../../../../common/lib/kibana';
-import { timelineSelectors } from '../../../store/timeline';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineSelectors } from '../../../store';
+import { timelineDefaults } from '../../../store/defaults';
import { combineQueries } from '../../../../common/lib/kuery';
import {
endSelector,
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx
index 963713a2317a6..0d794769b0887 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx
@@ -24,7 +24,7 @@ import styled from 'styled-components';
import type { EuiTheme } from '@kbn/react-kibana-context-styled';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import {
useDeepEqualSelector,
useShallowEqualSelector,
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/selectors.ts
index bc0317f4c4282..57e727818d5f4 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/selectors.ts
@@ -7,7 +7,7 @@
import { createSelector } from 'reselect';
-import { timelineSelectors } from '../../../store/timeline';
+import { timelineSelectors } from '../../../store';
export const getTimelineNoteSelector = () =>
createSelector(timelineSelectors.selectTimeline, (timeline) => {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx
index 87e423ce9483d..20eff77cfbaec 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/pinned_tab_content/index.tsx
@@ -15,7 +15,7 @@ import { connect } from 'react-redux';
import deepEqual from 'fast-deep-equal';
import type { ControlColumnProps } from '../../../../../common/types';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import type { CellValueElementProps } from '../cell_rendering';
import type { Direction } from '../../../../../common/search_strategy';
import { useTimelineEvents } from '../../../containers';
@@ -25,10 +25,10 @@ import { Footer, footerHeight } from '../footer';
import { requiredFieldsForActions } from '../../../../detections/components/alerts_table/default_config';
import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { useTimelineFullScreen } from '../../../../common/containers/use_full_screen';
-import type { TimelineModel } from '../../../store/timeline/model';
+import type { TimelineModel } from '../../../store/model';
import type { State } from '../../../../common/store';
import { calculateTotalPages } from '../helpers';
import type { RowRenderer, ToggleDetailPanel } from '../../../../../common/types/timeline';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx
index 919bca8308d89..4e98a4839866f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.test.tsx
@@ -13,7 +13,7 @@ import type { NewTimelineProps } from './helpers';
import { AddToFavoritesButton, NewTimeline } from './helpers';
import { useCreateTimelineButton } from './use_create_timeline';
import { kibanaObservable, TestProviders } from '../../../../common/mock/test_providers';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { TimelineId } from '../../../../../common/types/timeline';
import { TimelineStatus, TimelineType } from '../../../../../common/api/timeline';
import {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx
index b8c0366e3f39e..c6c252ddde870 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx
@@ -12,12 +12,12 @@ import { useDispatch } from 'react-redux';
import type { TimelineTypeLiteral } from '../../../../../common/api/timeline';
import { TimelineType, TimelineStatus } from '../../../../../common/api/timeline';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import { useShallowEqualSelector } from '../../../../common/hooks/use_selector';
import * as i18n from './translations';
import { useCreateTimelineButton } from './use_create_timeline';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { TIMELINE_TOUR_CONFIG_ANCHORS } from '../tour/step_config';
const NotesCountBadge = styled(EuiBadge)`
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx
index 0693901bf2114..10f328f198c9c 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/use_create_timeline.tsx
@@ -11,7 +11,7 @@ import { EuiButton, EuiButtonEmpty } from '@elastic/eui';
import { InputsModelId } from '../../../../common/store/inputs/constants';
import { defaultHeaders } from '../body/column_headers/default_headers';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import { useTimelineFullScreen } from '../../../../common/containers/use_full_screen';
import { TimelineId } from '../../../../../common/types/timeline';
import type { TimelineTypeLiteral } from '../../../../../common/api/timeline';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx
index 70ea6638a66ee..cbfa6b44590b3 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx
@@ -24,7 +24,7 @@ import type { FieldValueQueryBar } from '../../../../../detections/components/ru
import type { FormSchema } from '../../../../../shared_imports';
import { Form, UseField, useForm, useFormData } from '../../../../../shared_imports';
-import { timelineActions } from '../../../../store/timeline';
+import { timelineActions } from '../../../../store';
import * as i18n from '../translations';
import { getEqlOptions } from './selectors';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/selectors.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/selectors.tsx
index 9c3555f2fb710..e533ef9175178 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/selectors.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/selectors.tsx
@@ -6,7 +6,7 @@
*/
import { createSelector } from 'reselect';
-import { selectTimeline } from '../../../../store/timeline/selectors';
+import { selectTimeline } from '../../../../store/selectors';
export const getEqlOptions = () =>
createSelector(
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx
index e1e732b32e479..73d83469413c4 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/index.tsx
@@ -20,13 +20,13 @@ import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery';
-import type { KqlMode } from '../../../store/timeline/model';
+import type { KqlMode } from '../../../store/model';
import { useSavedQueryServices } from '../../../../common/utils/saved_query_services';
import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker';
import { QueryBar } from '../../../../common/components/query_bar';
import type { DataProvider } from '../data_providers/data_provider';
import { buildGlobalQuery } from '../helpers';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import type { KueryFilterQuery, KueryFilterQueryKind } from '../../../../../common/types/timeline';
export interface QueryBarTimelineComponentProps {
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx
index 8d70c3e4d44c3..553b71705884b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/index.tsx
@@ -15,9 +15,9 @@ import { euiThemeVars } from '@kbn/ui-theme';
import type { TimelineStatusLiteralWithNull } from '../../../../../../common/api/timeline';
import { TimelineStatus, TimelineType } from '../../../../../../common/api/timeline';
-import { timelineSelectors } from '../../../../store/timeline';
+import { timelineSelectors } from '../../../../store';
import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector';
-import { timelineDefaults } from '../../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../../store/defaults';
import * as i18n from './translations';
import { StatefulSearchOrFilter } from '../../search_or_filter';
import { DataProviders } from '../../data_providers';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts
index 02668c18b308c..62c0134b96612 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/header/selectors.ts
@@ -7,7 +7,7 @@
import { createSelector } from 'reselect';
-import { timelineSelectors } from '../../../../store/timeline';
+import { timelineSelectors } from '../../../../store';
export const getTimelineSaveModalByIdSelector = () =>
createSelector(timelineSelectors.selectTimeline, (timeline) => ({
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx
index 390369eaf89ed..be05ff81f53c2 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.tsx
@@ -27,7 +27,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common';
import type { ControlColumnProps } from '../../../../../common/types';
import { InputsModelId } from '../../../../common/store/inputs/constants';
import { useInvalidFilterQuery } from '../../../../common/hooks/use_invalid_filter_query';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
+import { timelineActions, timelineSelectors } from '../../../store';
import type { CellValueElementProps } from '../cell_rendering';
import type { Direction, TimelineItem } from '../../../../../common/search_strategy';
import { useTimelineEvents } from '../../../containers';
@@ -50,10 +50,10 @@ import { EventDetailsWidthProvider } from '../../../../common/components/events_
import type { inputsModel, State } from '../../../../common/store';
import { inputsSelectors } from '../../../../common/store';
import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineDefaults } from '../../../store/defaults';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import { useTimelineEventsCountPortal } from '../../../../common/hooks/use_timeline_events_count';
-import type { TimelineModel } from '../../../store/timeline/model';
+import type { TimelineModel } from '../../../store/model';
import { useTimelineFullScreen } from '../../../../common/containers/use_full_screen';
import { activeTimeline } from '../../../containers/active_timeline_context';
import { DetailsPanel } from '../../side_panel';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/helpers.tsx
index e8db433c0a117..282d94b873e83 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/helpers.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/helpers.tsx
@@ -12,7 +12,7 @@ import styled from 'styled-components';
import { AndOrBadge } from '../../../../common/components/and_or_badge';
import * as i18n from './translations';
-import type { KqlMode } from '../../../store/timeline/model';
+import type { KqlMode } from '../../../store/model';
const AndOrContainer = styled.div`
position: relative;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/index.tsx
index 7dc5e7909093d..cdd6fc793082f 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/index.tsx
@@ -25,12 +25,12 @@ import { SourcererScopeName } from '../../../../common/store/sourcerer/model';
import { useSourcererDataView } from '../../../../common/containers/sourcerer';
import type { State, inputsModel } from '../../../../common/store';
import { inputsSelectors } from '../../../../common/store';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
-import type { KqlMode, TimelineModel } from '../../../store/timeline/model';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineActions, timelineSelectors } from '../../../store';
+import type { KqlMode, TimelineModel } from '../../../store/model';
+import { timelineDefaults } from '../../../store/defaults';
import { dispatchUpdateReduxTime } from '../../../../common/components/super_date_picker';
import { SearchOrFilter } from './search_or_filter';
-import { setDataProviderVisibility } from '../../../store/timeline/actions';
+import { setDataProviderVisibility } from '../../../store/actions';
import * as i18n from './translations';
const FilterItemsContainer = styled(EuiFlexGroup)``;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx
index e822dfb7e0dcf..16f053b4abb75 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_or_filter/search_or_filter.tsx
@@ -13,7 +13,7 @@ import type { Filter } from '@kbn/es-query';
import type { FilterManager } from '@kbn/data-plugin/public';
import { TimelineType } from '../../../../../common/api/timeline';
import { InputsModelId } from '../../../../common/store/inputs/constants';
-import type { KqlMode } from '../../../store/timeline/model';
+import type { KqlMode } from '../../../store/model';
import type { DispatchUpdateReduxTime } from '../../../../common/components/super_date_picker';
import { SuperDatePicker } from '../../../../common/components/super_date_picker';
import type { KueryFilterQuery } from '../../../../../common/types/timeline';
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx
index d4459f8de4a9a..2f40cb20877dd 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/session_tab_content/use_session_view.tsx
@@ -33,8 +33,8 @@ import {
} from '../../../../common/containers/use_full_screen';
import { detectionsTimelineIds } from '../../../containers/helpers';
import { useUserPrivileges } from '../../../../common/components/user_privileges';
-import { timelineActions, timelineSelectors } from '../../../store/timeline';
-import { timelineDefaults } from '../../../store/timeline/defaults';
+import { timelineActions, timelineSelectors } from '../../../store';
+import { timelineDefaults } from '../../../store/defaults';
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector';
const FullScreenButtonIcon = styled(EuiButtonIcon)`
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx
index 4deaf849b6272..cc4d28f30554b 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/index.tsx
@@ -31,7 +31,7 @@ import {
EqlEventsCountBadge,
TimelineEventsCountBadge,
} from '../../../../common/hooks/use_timeline_events_count';
-import { timelineActions } from '../../../store/timeline';
+import { timelineActions } from '../../../store';
import type { CellValueElementProps } from '../cell_rendering';
import {
getActiveTabSelector,
@@ -44,7 +44,7 @@ import {
import * as i18n from './translations';
import { useLicense } from '../../../../common/hooks/use_license';
import { TIMELINE_CONVERSATION_TITLE } from '../../../../assistant/content/conversations/translations';
-import { initializeTimelineSettings } from '../../../store/timeline/actions';
+import { initializeTimelineSettings } from '../../../store/actions';
import { DISCOVER_ESQL_IN_TIMELINE_TECHNICAL_PREVIEW } from './translations';
const HideShowContainer = styled.div.attrs<{ $isVisible: boolean; isOverflowYScroll: boolean }>(
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts
index 04045e94aee25..1d82a1e228032 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs_content/selectors.ts
@@ -8,7 +8,7 @@
import { createSelector } from 'reselect';
import { TimelineTabs } from '../../../../../common/types/timeline';
import { selectNotesById } from '../../../../common/store/app/selectors';
-import { selectTimeline } from '../../../store/timeline/selectors';
+import { selectTimeline } from '../../../store/selectors';
export const getActiveTabSelector = () =>
createSelector(selectTimeline, (timeline) => timeline?.activeTab ?? TimelineTabs.query);
diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx
index f7902dacf5e68..81252216c529d 100644
--- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx
@@ -23,7 +23,7 @@ import type { inputsModel } from '../../common/store';
import type { RunTimeMappings } from '../../common/store/sourcerer/model';
import { useKibana } from '../../common/lib/kibana';
import { createFilter } from '../../common/containers/helpers';
-import { timelineActions } from '../store/timeline';
+import { timelineActions } from '../store';
import { detectionsTimelineIds } from './helpers';
import { getInspectResponse } from '../../helpers';
import type {
diff --git a/x-pack/plugins/security_solution/public/timelines/index.ts b/x-pack/plugins/security_solution/public/timelines/index.ts
index 71c15088d1acf..91078fa0420b1 100644
--- a/x-pack/plugins/security_solution/public/timelines/index.ts
+++ b/x-pack/plugins/security_solution/public/timelines/index.ts
@@ -7,8 +7,8 @@
import type { SecuritySubPluginWithStore } from '../app/types';
import { routes } from './routes';
-import { initialTimelineState, timelineReducer } from './store/timeline/reducer';
-import type { TimelineState } from './store/timeline/types';
+import { initialTimelineState, timelineReducer } from './store/reducer';
+import type { TimelineState } from './store/types';
export class Timelines {
public setup() {}
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts b/x-pack/plugins/security_solution/public/timelines/store/actions.ts
similarity index 95%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts
rename to x-pack/plugins/security_solution/public/timelines/store/actions.ts
index 8440a534ad45d..8de7d6670e28e 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/actions.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/actions.ts
@@ -9,19 +9,19 @@ import actionCreatorFactory from 'typescript-fsa';
import type { Filter } from '@kbn/es-query';
import type { SavedSearch } from '@kbn/saved-search-plugin/common';
-import type { SessionViewConfig } from '../../../../common/types';
+import type { SessionViewConfig } from '../../../common/types';
import type {
DataProvider,
DataProviderType,
QueryOperator,
-} from '../../components/timeline/data_providers/data_provider';
+} from '../components/timeline/data_providers/data_provider';
import type { KqlMode, TimelineModel } from './model';
import type { InitialyzeTimelineSettings, InsertTimeline } from './types';
import type {
FieldsEqlOptions,
TimelineNonEcsData,
-} from '../../../../common/search_strategy/timeline';
+} from '../../../common/search_strategy/timeline';
import type {
TimelineTabs,
TimelinePersistInput,
@@ -29,9 +29,9 @@ import type {
ToggleDetailPanel,
ColumnHeaderOptions,
SortColumnTimeline,
-} from '../../../../common/types/timeline';
-import type { RowRendererId } from '../../../../common/api/timeline';
-import type { ResolveTimelineConfig } from '../../components/open_timeline/types';
+} from '../../../common/types/timeline';
+import type { RowRendererId } from '../../../common/api/timeline';
+import type { ResolveTimelineConfig } from '../components/open_timeline/types';
const actionCreator = actionCreatorFactory('x-pack/security_solution/local/timeline');
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts
similarity index 87%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts
rename to x-pack/plugins/security_solution/public/timelines/store/defaults.ts
index 1df0a997a2d8e..9fb94d9f5b1b9 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/defaults.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts
@@ -5,11 +5,11 @@
* 2.0.
*/
-import { TimelineTabs } from '../../../../common/types/timeline';
-import { TimelineType, TimelineStatus } from '../../../../common/api/timeline';
+import { TimelineTabs } from '../../../common/types/timeline';
+import { TimelineType, TimelineStatus } from '../../../common/api/timeline';
-import { defaultHeaders } from '../../components/timeline/body/column_headers/default_headers';
-import { normalizeTimeRange } from '../../../common/utils/normalize_time_range';
+import { defaultHeaders } from '../components/timeline/body/column_headers/default_headers';
+import { normalizeTimeRange } from '../../common/utils/normalize_time_range';
import type { SubsetTimelineModel, TimelineModel } from './model';
// normalizeTimeRange uses getTimeRangeSettings which cannot be used outside Kibana context if the uiSettings is not false
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts b/x-pack/plugins/security_solution/public/timelines/store/epic.test.ts
similarity index 97%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic.test.ts
index 9a273bc6ca14a..bbcc9363a1072 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.test.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/epic.test.ts
@@ -7,9 +7,9 @@
import type { Filter } from '@kbn/es-query';
import { FilterStateStore } from '@kbn/es-query';
-import { Direction } from '../../../../common/search_strategy';
-import { TimelineTabs } from '../../../../common/types/timeline';
-import { TimelineType, TimelineStatus } from '../../../../common/api/timeline';
+import { Direction } from '../../../common/search_strategy';
+import { TimelineTabs } from '../../../common/types/timeline';
+import { TimelineType, TimelineStatus } from '../../../common/api/timeline';
import { convertTimelineAsInput } from './epic';
import type { TimelineModel } from './model';
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts b/x-pack/plugins/security_solution/public/timelines/store/epic.ts
similarity index 96%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic.ts
index 7c072abce73e0..d3c14c3a1e2c5 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/epic.ts
@@ -29,15 +29,15 @@ import {
takeUntil,
} from 'rxjs/operators';
-import type { TimelineErrorResponse, TimelineResponse } from '../../../../common/api/timeline';
-import type { ColumnHeaderOptions } from '../../../../common/types/timeline';
-import { TimelineStatus, TimelineType } from '../../../../common/api/timeline';
-import type { inputsModel } from '../../../common/store/inputs';
-import { addError } from '../../../common/store/app/actions';
+import type { TimelineErrorResponse, TimelineResponse } from '../../../common/api/timeline';
+import type { ColumnHeaderOptions } from '../../../common/types/timeline';
+import { TimelineStatus, TimelineType } from '../../../common/api/timeline';
+import type { inputsModel } from '../../common/store/inputs';
+import { addError } from '../../common/store/app/actions';
-import { copyTimeline, persistTimeline } from '../../containers/api';
-import { ALL_TIMELINE_QUERY_ID } from '../../containers/all';
-import * as i18n from '../../pages/translations';
+import { copyTimeline, persistTimeline } from '../containers/api';
+import { ALL_TIMELINE_QUERY_ID } from '../containers/all';
+import * as i18n from '../pages/translations';
import {
updateTimeline,
@@ -57,7 +57,7 @@ import { isNotNull } from './helpers';
import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue';
import { myEpicTimelineId } from './my_epic_timeline_id';
import type { TimelineEpicDependencies } from './types';
-import type { TimelineInput } from '../../../../common/search_strategy';
+import type { TimelineInput } from '../../../common/search_strategy';
const isItAtimelineAction = (timelineId: string | undefined) =>
timelineId && timelineId.toLowerCase().startsWith('timeline');
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts b/x-pack/plugins/security_solution/public/timelines/store/epic_changed.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic_changed.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic_changed.ts
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_dispatcher_timeline_persistence_queue.ts b/x-pack/plugins/security_solution/public/timelines/store/epic_dispatcher_timeline_persistence_queue.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic_dispatcher_timeline_persistence_queue.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic_dispatcher_timeline_persistence_queue.ts
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts b/x-pack/plugins/security_solution/public/timelines/store/epic_favorite.ts
similarity index 92%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic_favorite.ts
index ff501fb4761de..c6bd77d222a6c 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_favorite.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/epic_favorite.ts
@@ -12,7 +12,7 @@ import type { Observable } from 'rxjs';
import { from, EMPTY } from 'rxjs';
import { filter, mergeMap, withLatestFrom, startWith, takeUntil } from 'rxjs/operators';
-import { addError } from '../../../common/store/app/actions';
+import { addError } from '../../common/store/app/actions';
import {
endTimelineSaving,
updateIsFavorite,
@@ -23,10 +23,10 @@ import {
import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue';
import { myEpicTimelineId } from './my_epic_timeline_id';
import type { TimelineById } from './types';
-import type { inputsModel } from '../../../common/store/inputs';
-import type { ResponseFavoriteTimeline } from '../../../../common/api/timeline';
-import { TimelineType } from '../../../../common/api/timeline';
-import { persistFavorite } from '../../containers/api';
+import type { inputsModel } from '../../common/store/inputs';
+import type { ResponseFavoriteTimeline } from '../../../common/api/timeline';
+import { TimelineType } from '../../../common/api/timeline';
+import { persistFavorite } from '../containers/api';
type FavoriteTimelineAction = ReturnType;
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts b/x-pack/plugins/security_solution/public/timelines/store/epic_note.ts
similarity index 93%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic_note.ts
index 01e612302ca31..98c4f90bfa1dd 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_note.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/epic_note.ts
@@ -12,9 +12,9 @@ import type { Observable } from 'rxjs';
import { from, EMPTY } from 'rxjs';
import { filter, mergeMap, switchMap, withLatestFrom, startWith, takeUntil } from 'rxjs/operators';
-import { updateNote, addError } from '../../../common/store/app/actions';
-import type { NotesById } from '../../../common/store/app/model';
-import type { inputsModel } from '../../../common/store/inputs';
+import { updateNote, addError } from '../../common/store/app/actions';
+import type { NotesById } from '../../common/store/app/model';
+import type { inputsModel } from '../../common/store/inputs';
import {
addNote,
@@ -27,8 +27,8 @@ import {
import { myEpicTimelineId } from './my_epic_timeline_id';
import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue';
import type { TimelineById } from './types';
-import { persistNote } from '../../containers/notes/api';
-import type { ResponseNote } from '../../../../common/api/timeline';
+import { persistNote } from '../containers/notes/api';
+import type { ResponseNote } from '../../../common/api/timeline';
type NoteAction = ReturnType;
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts b/x-pack/plugins/security_solution/public/timelines/store/epic_pinned_event.ts
similarity index 94%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts
rename to x-pack/plugins/security_solution/public/timelines/store/epic_pinned_event.ts
index b99de117e785e..0808479bd5f24 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_pinned_event.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/epic_pinned_event.ts
@@ -12,9 +12,9 @@ import type { Observable } from 'rxjs';
import { from, EMPTY } from 'rxjs';
import { filter, mergeMap, startWith, withLatestFrom, takeUntil } from 'rxjs/operators';
-import { addError } from '../../../common/store/app/actions';
-import type { inputsModel } from '../../../common/store/inputs';
-import type { PinnedEventResponse } from '../../../../common/api/timeline';
+import { addError } from '../../common/store/app/actions';
+import type { inputsModel } from '../../common/store/inputs';
+import type { PinnedEventResponse } from '../../../common/api/timeline';
import {
pinEvent,
endTimelineSaving,
@@ -26,7 +26,7 @@ import {
import { myEpicTimelineId } from './my_epic_timeline_id';
import { dispatcherTimelinePersistQueue } from './epic_dispatcher_timeline_persistence_queue';
import type { TimelineById } from './types';
-import { persistPinnedEvent } from '../../containers/pinned_event/api';
+import { persistPinnedEvent } from '../containers/pinned_event/api';
type PinnedEventAction = ReturnType;
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts
similarity index 98%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts
rename to x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts
index e0ca1b6dc681d..2e3376396fb78 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.test.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts
@@ -6,25 +6,20 @@
*/
import { cloneDeep } from 'lodash/fp';
-import type { ColumnHeaderOptions } from '../../../../common/types/timeline';
-import { TimelineTabs, TimelineId } from '../../../../common/types/timeline';
-import { TimelineType, TimelineStatus } from '../../../../common/api/timeline';
-
+import type { ColumnHeaderOptions } from '../../../common/types/timeline';
+import { TimelineTabs, TimelineId } from '../../../common/types/timeline';
+import { TimelineType, TimelineStatus } from '../../../common/api/timeline';
import type {
DataProvider,
DataProvidersAnd,
-} from '../../components/timeline/data_providers/data_provider';
-import {
- IS_OPERATOR,
- DataProviderType,
-} from '../../components/timeline/data_providers/data_provider';
-import { defaultColumnHeaderType } from '../../components/timeline/body/column_headers/default_headers';
+} from '../components/timeline/data_providers/data_provider';
+import { IS_OPERATOR, DataProviderType } from '../components/timeline/data_providers/data_provider';
+import { defaultColumnHeaderType } from '../components/timeline/body/column_headers/default_headers';
import {
DEFAULT_COLUMN_MIN_WIDTH,
RESIZED_COLUMN_MIN_WITH,
-} from '../../components/timeline/body/constants';
-import { defaultHeaders } from '../../../common/mock';
-
+} from '../components/timeline/body/constants';
+import { defaultHeaders } from '../../common/mock';
import {
addNewTimeline,
addTimelineProviders,
@@ -49,12 +44,12 @@ import {
import type { TimelineModel } from './model';
import { timelineDefaults } from './defaults';
import type { TimelineById } from './types';
-import { Direction } from '../../../../common/search_strategy';
+import { Direction } from '../../../common/search_strategy';
import type { FilterManager } from '@kbn/data-plugin/public';
-jest.mock('../../../common/utils/normalize_time_range');
-jest.mock('../../../common/utils/default_date_settings', () => {
- const actual = jest.requireActual('../../../common/utils/default_date_settings');
+jest.mock('../../common/utils/normalize_time_range');
+jest.mock('../../common/utils/default_date_settings', () => {
+ const actual = jest.requireActual('../../common/utils/default_date_settings');
return {
...actual,
DEFAULT_FROM_MOMENT: new Date('2020-10-27T11:37:31.655Z'),
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts
similarity index 97%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts
rename to x-pack/plugins/security_solution/public/timelines/store/helpers.ts
index ca890b9ac3ec4..3206bb96e89ad 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/helpers.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts
@@ -6,24 +6,21 @@
*/
import { getOr, omit, uniq, isEmpty, isEqualWith, cloneDeep, union } from 'lodash/fp';
-
import { v4 as uuidv4 } from 'uuid';
-
import type { Filter } from '@kbn/es-query';
-
-import type { SessionViewConfig, ExpandedDetailTimeline } from '../../../../common/types';
-import type { TimelineNonEcsData } from '../../../../common/search_strategy';
-import type { Sort } from '../../components/timeline/body/sort';
+import type { SessionViewConfig, ExpandedDetailTimeline } from '../../../common/types';
+import type { TimelineNonEcsData } from '../../../common/search_strategy';
+import type { Sort } from '../components/timeline/body/sort';
import type {
DataProvider,
QueryOperator,
QueryMatch,
-} from '../../components/timeline/data_providers/data_provider';
+} from '../components/timeline/data_providers/data_provider';
import {
DataProviderType,
IS_OPERATOR,
EXISTS_OPERATOR,
-} from '../../components/timeline/data_providers/data_provider';
+} from '../components/timeline/data_providers/data_provider';
import type {
ColumnHeaderOptions,
TimelineEventsType,
@@ -31,25 +28,22 @@ import type {
TimelinePersistInput,
ToggleDetailPanel,
SortColumnTimeline,
-} from '../../../../common/types/timeline';
-import type { RowRendererId, TimelineTypeLiteral } from '../../../../common/api/timeline';
-import { TimelineId } from '../../../../common/types/timeline';
-import { TimelineStatus, TimelineType } from '../../../../common/api/timeline';
-import { normalizeTimeRange } from '../../../common/utils/normalize_time_range';
+} from '../../../common/types/timeline';
+import type { RowRendererId, TimelineTypeLiteral } from '../../../common/api/timeline';
+import { TimelineId } from '../../../common/types/timeline';
+import { TimelineStatus, TimelineType } from '../../../common/api/timeline';
+import { normalizeTimeRange } from '../../common/utils/normalize_time_range';
import { getTimelineManageDefaults, timelineDefaults } from './defaults';
import type { KqlMode, TimelineModel } from './model';
import type { TimelineById, TimelineModelSettings } from './types';
-import {
- DEFAULT_FROM_MOMENT,
- DEFAULT_TO_MOMENT,
-} from '../../../common/utils/default_date_settings';
+import { DEFAULT_FROM_MOMENT, DEFAULT_TO_MOMENT } from '../../common/utils/default_date_settings';
import {
DEFAULT_COLUMN_MIN_WIDTH,
RESIZED_COLUMN_MIN_WITH,
-} from '../../components/timeline/body/constants';
-import { activeTimeline } from '../../containers/active_timeline_context';
-import type { ResolveTimelineConfig } from '../../components/open_timeline/types';
-import { getDisplayValue } from '../../components/timeline/data_providers/helpers';
+} from '../components/timeline/body/constants';
+import { activeTimeline } from '../containers/active_timeline_context';
+import type { ResolveTimelineConfig } from '../components/open_timeline/types';
+import { getDisplayValue } from '../components/timeline/data_providers/helpers';
export const isNotNull = (value: T | null): value is T => value !== null;
interface AddTimelineNoteParams {
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/index.ts b/x-pack/plugins/security_solution/public/timelines/store/index.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/index.ts
rename to x-pack/plugins/security_solution/public/timelines/store/index.ts
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/manage_timeline_id.tsx b/x-pack/plugins/security_solution/public/timelines/store/manage_timeline_id.tsx
similarity index 100%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/manage_timeline_id.tsx
rename to x-pack/plugins/security_solution/public/timelines/store/manage_timeline_id.tsx
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts b/x-pack/plugins/security_solution/public/timelines/store/model.ts
similarity index 96%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts
rename to x-pack/plugins/security_solution/public/timelines/store/model.ts
index 47e15be86e2a1..0bd6f4806f06b 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/model.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/model.ts
@@ -8,11 +8,11 @@
import type { FilterManager } from '@kbn/data-plugin/public';
import type { Filter } from '@kbn/es-query';
import type { SavedSearch } from '@kbn/saved-search-plugin/common';
-import type { ExpandedDetailTimeline, SessionViewConfig } from '../../../../common/types';
+import type { ExpandedDetailTimeline, SessionViewConfig } from '../../../common/types';
import type {
EqlOptionsSelected,
TimelineNonEcsData,
-} from '../../../../common/search_strategy/timeline';
+} from '../../../common/search_strategy/timeline';
import type {
TimelineTabs,
ScrollToTopEvent,
@@ -21,14 +21,14 @@ import type {
DataProvider,
SerializedFilterQuery,
TimelineEventsType,
-} from '../../../../common/types/timeline';
+} from '../../../common/types/timeline';
import type {
RowRendererId,
TimelineStatus,
TimelineType,
PinnedEvent,
-} from '../../../../common/api/timeline';
-import type { ResolveTimelineConfig } from '../../components/open_timeline/types';
+} from '../../../common/api/timeline';
+import type { ResolveTimelineConfig } from '../components/open_timeline/types';
export type KqlMode = 'filter' | 'search';
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/my_epic_timeline_id.ts b/x-pack/plugins/security_solution/public/timelines/store/my_epic_timeline_id.ts
similarity index 100%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/my_epic_timeline_id.ts
rename to x-pack/plugins/security_solution/public/timelines/store/my_epic_timeline_id.ts
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts b/x-pack/plugins/security_solution/public/timelines/store/reducer.ts
similarity index 99%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts
rename to x-pack/plugins/security_solution/public/timelines/store/reducer.ts
index 6947b207874a7..1ae41833a14bb 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/reducer.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/reducer.ts
@@ -106,7 +106,7 @@ import {
import type { TimelineState } from './types';
import { EMPTY_TIMELINE_BY_ID } from './types';
-import { TimelineType } from '../../../../common/api/timeline';
+import { TimelineType } from '../../../common/api/timeline';
export const initialTimelineState: TimelineState = {
timelineById: EMPTY_TIMELINE_BY_ID,
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts b/x-pack/plugins/security_solution/public/timelines/store/selectors.ts
similarity index 97%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts
rename to x-pack/plugins/security_solution/public/timelines/store/selectors.ts
index d4078373aaff1..f22dcb3b96fe8 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/selectors.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/selectors.ts
@@ -6,7 +6,7 @@
*/
import { createSelector } from 'reselect';
-import type { State } from '../../../common/store/types';
+import type { State } from '../../common/store/types';
import type { TimelineModel } from './model';
import type { InsertTimeline, TimelineById } from './types';
diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts b/x-pack/plugins/security_solution/public/timelines/store/types.ts
similarity index 87%
rename from x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts
rename to x-pack/plugins/security_solution/public/timelines/store/types.ts
index 2d45367b937b8..741b906dcdebe 100644
--- a/x-pack/plugins/security_solution/public/timelines/store/timeline/types.ts
+++ b/x-pack/plugins/security_solution/public/timelines/store/types.ts
@@ -7,11 +7,11 @@
import type { FilterManager } from '@kbn/data-plugin/public';
import type { TableById } from '@kbn/securitysolution-data-table';
-import type { RootEpicDependencies } from '../../../common/store/epic';
-import type { ColumnHeaderOptions, SortColumnTimeline } from '../../../../common/types';
-import type { RowRendererId } from '../../../../common/api/timeline';
-import type { inputsModel } from '../../../common/store/inputs';
-import type { NotesById } from '../../../common/store/app/model';
+import type { RootEpicDependencies } from '../../common/store/epic';
+import type { ColumnHeaderOptions, SortColumnTimeline } from '../../../common/types';
+import type { RowRendererId } from '../../../common/api/timeline';
+import type { inputsModel } from '../../common/store/inputs';
+import type { NotesById } from '../../common/store/app/model';
import type { TimelineModel } from './model';
From 1004ddb9720f0763a6d0d95f76ef9dc9157e4500 Mon Sep 17 00:00:00 2001
From: Luke G <11671118+lgestc@users.noreply.github.com>
Date: Tue, 19 Dec 2023 17:01:23 +0100
Subject: [PATCH 11/95] [Security Solution] Fix flaky sourcerer timeline test
(#173288)
## Summary
This hopefully #fixes https://github.com/elastic/kibana/issues/169402
What was fixed:
It seems that the options selected in the sourcerer dropdown were no
longer valid. I am now altering the default value which will always be
there.
Flaky test runner build:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4573#018c68c9-08c0-4c87-8554-97a1fe1650db
---
.../sourcerer/sourcerer_timeline.cy.ts | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/sourcerer/sourcerer_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/sourcerer/sourcerer_timeline.cy.ts
index 8e7be3970440e..30e1e39b4cd3e 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/sourcerer/sourcerer_timeline.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/sourcerer/sourcerer_timeline.cy.ts
@@ -37,10 +37,9 @@ import { getTimeline, getTimelineModifiedSourcerer } from '../../../../objects/t
import { closeTimeline, openTimelineById } from '../../../../tasks/timeline';
const siemDataViewTitle = 'Security Default Data View';
-const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,*beat*,siem-read*,.kibana*,fakebeat-*'];
+const dataViews = ['logs-*', 'metrics-*', '.kibana-event-log-*'];
-// TODO: https://github.com/elastic/kibana/issues/161539
-describe.skip('Timeline scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
+describe('Timeline scope', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => {
beforeEach(() => {
cy.clearLocalStorage();
login();
@@ -78,12 +77,8 @@ describe.skip('Timeline scope', { tags: ['@ess', '@serverless', '@brokenInServer
it('shows modified badge when index patterns change and removes when reset', () => {
openTimelineUsingToggle();
openSourcerer('timeline');
- openDataViewSelection();
- cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
- isDataViewSelection(dataViews[1]);
openAdvancedSettings();
- const patterns = dataViews[1].split(',');
- deselectSourcererOptions([patterns[0]]);
+ deselectSourcererOptions(['.alerts-security.alerts-default']);
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`exist`);
openSourcerer('timeline');
From e17e3e4678aa07162fd26ac1c7660ec770ccf076 Mon Sep 17 00:00:00 2001
From: Philippe Oberti
Date: Tue, 19 Dec 2023 10:02:50 -0600
Subject: [PATCH 12/95] [Security Solution] - skipping failing Cypress test
(#173641)
---
.../e2e/investigations/alerts/changing_alert_status.cy.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 2dc4a360134b2..e8426c4599fb5 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
@@ -158,7 +158,7 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, ()
});
});
});
- context('Closing alerts', () => {
+ context.skip('Closing alerts', () => {
beforeEach(() => {
login();
deleteAlertsAndRules();
From a57b5a0f13ff8d47a5d4be02cbb6df2469cf197d Mon Sep 17 00:00:00 2001
From: Philippe Oberti
Date: Tue, 19 Dec 2023 10:21:32 -0600
Subject: [PATCH 13/95] [Security Solution] - skipping failing Cypress test
(#173646)
---
.../cypress/e2e/investigations/timelines/full_screen.cy.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts
index bf69b711a7aef..ea9742a9c0829 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/full_screen.cy.ts
@@ -18,7 +18,7 @@ import { populateTimeline } from '../../../tasks/timeline';
import { hostsUrl } from '../../../urls/navigation';
-describe('Toggle full screen', { tags: ['@ess', '@serverless'] }, () => {
+describe.skip('Toggle full screen', { tags: ['@ess', '@serverless'] }, () => {
beforeEach(() => {
login();
visitWithTimeRange(hostsUrl('allHosts'));
From f31b56afe2fa7127bb7948626576d4e678444e2d Mon Sep 17 00:00:00 2001
From: Philippe Oberti
Date: Tue, 19 Dec 2023 11:04:51 -0600
Subject: [PATCH 14/95] [Security Solution] - skipping failing Cypress tests
(#173642)
---
.../cypress/e2e/investigations/alerts/alerts_details.cy.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
index 7e5e19b464c4a..0f24575d8a2a2 100644
--- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
+++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_details.cy.ts
@@ -82,7 +82,7 @@ describe('Alert details flyout', { tags: ['@ess', '@serverless'] }, () => {
cy.task('esArchiverUnload', 'unmapped_fields');
});
- it('should display user and system defined highlighted fields', () => {
+ it.skip('should display user and system defined highlighted fields', () => {
cy.get(SUMMARY_VIEW)
.should('be.visible')
.and('contain.text', 'event.kind')
@@ -161,7 +161,7 @@ describe('Alert details flyout', { tags: ['@ess', '@serverless'] }, () => {
cy.url().should('not.include', 'eventFlyout=');
});
- it('should open the alert flyout when the page is refreshed', () => {
+ it.skip('should open the alert flyout when the page is refreshed', () => {
cy.get(OVERVIEW_RULE).should('be.visible');
cy.reload();
cy.get(OVERVIEW_RULE).should('be.visible');
@@ -172,7 +172,7 @@ describe('Alert details flyout', { tags: ['@ess', '@serverless'] }, () => {
cy.get(COPY_ALERT_FLYOUT_LINK).should('be.visible');
});
- it('should have the `kibana.alert.url` field set', () => {
+ it.skip('should have the `kibana.alert.url` field set', () => {
openTable();
filterBy('kibana.alert.url');
cy.get('[data-test-subj="formatted-field-kibana.alert.url"]').should(
From 4ae07aa0d0e79b869218c71dac0ed7afa69736f8 Mon Sep 17 00:00:00 2001
From: Kevin Logan <56395104+kevinlog@users.noreply.github.com>
Date: Tue, 19 Dec 2023 12:05:17 -0500
Subject: [PATCH 15/95] [Security Solution] Skip flaky suites (#173667)
## Summary
Skip suites failing in Serverless. Will also backport to 8.12.
### 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
---
.../cypress/e2e/artifacts/artifacts_mocked_data.cy.ts | 3 ++-
.../security_solution_endpoint/apps/endpoint/endpoint_list.ts | 3 ++-
.../apps/integrations/policy_details.ts | 3 ++-
.../apis/endpoint_response_actions/execute.ts | 3 ++-
4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts
index e7f32820c00d7..55a1035ca8969 100644
--- a/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts
+++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/artifacts/artifacts_mocked_data.cy.ts
@@ -31,7 +31,8 @@ const loginWithoutAccess = (url: string) => {
loadPage(url);
};
-describe('Artifacts pages', { tags: ['@ess', '@serverless'] }, () => {
+// Flaky: https://github.com/elastic/kibana/issues/171168
+describe.skip('Artifacts pages', { tags: ['@ess', '@serverless'] }, () => {
let endpointData: ReturnTypeFromChainable | undefined;
before(() => {
diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
index f1edd7a45800c..0f65111b81e5b 100644
--- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
@@ -85,7 +85,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
return tableData;
};
- describe('endpoint list', function () {
+ // Flaky: https://github.com/elastic/kibana/issues/170357
+ describe.skip('endpoint list', function () {
targetTags(this, ['@ess', '@serverless']);
let indexedData: IndexedHostsAndAlertsResponse;
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
index b48c64b5e9dd4..efa7e6e505780 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
@@ -28,7 +28,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const endpointTestResources = getService('endpointTestResources');
const retry = getService('retry');
- describe('When on the Endpoint Policy Details Page', function () {
+ // Flaky: https://github.com/elastic/kibana/issues/171653
+ describe.skip('When on the Endpoint Policy Details Page', function () {
targetTags(this, ['@ess', '@serverless']);
let indexedData: IndexedHostsAndAlertsResponse;
diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
index f904539dae231..b11b83df5a235 100644
--- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
+++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
@@ -16,7 +16,8 @@ export default function ({ getService }: FtrProviderContext) {
const supertestWithoutAuth = getService('supertestWithoutAuth');
const endpointTestResources = getService('endpointTestResources');
- describe('Endpoint `execute` response action', function () {
+ // Flaky: https://github.com/elastic/kibana/issues/171666
+ describe.skip('Endpoint `execute` response action', function () {
targetTags(this, ['@ess', '@serverless']);
let indexedData: IndexedHostsAndAlertsResponse;
From 06fe6ec9c305cf038c70f7dcae30fbbff8f36774 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:17:24 +0000
Subject: [PATCH 16/95] skip flaky suite (#171654)
---
.../apps/integrations/policy_details.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
index efa7e6e505780..c415d3b9d8505 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
@@ -29,6 +29,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const retry = getService('retry');
// Flaky: https://github.com/elastic/kibana/issues/171653
+ // FLAKY: https://github.com/elastic/kibana/issues/171654
describe.skip('When on the Endpoint Policy Details Page', function () {
targetTags(this, ['@ess', '@serverless']);
From f543158278e53e25244104ea5f8e964c04c314a5 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:20:21 +0000
Subject: [PATCH 17/95] skip flaky suite (#171653)
---
.../apps/integrations/policy_details.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
index c415d3b9d8505..a2b1feaabd7cd 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/policy_details.ts
@@ -28,7 +28,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
const endpointTestResources = getService('endpointTestResources');
const retry = getService('retry');
- // Flaky: https://github.com/elastic/kibana/issues/171653
+ // FLAKY: https://github.com/elastic/kibana/issues/171653
// FLAKY: https://github.com/elastic/kibana/issues/171654
describe.skip('When on the Endpoint Policy Details Page', function () {
targetTags(this, ['@ess', '@serverless']);
From 2dce69eebc30ef849d3e8df61be8da73844eddf7 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:22:49 +0000
Subject: [PATCH 18/95] skip flaky suite (#171666)
---
.../apis/endpoint_response_actions/execute.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
index b11b83df5a235..1da78f53b3627 100644
--- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
+++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
@@ -16,7 +16,7 @@ export default function ({ getService }: FtrProviderContext) {
const supertestWithoutAuth = getService('supertestWithoutAuth');
const endpointTestResources = getService('endpointTestResources');
- // Flaky: https://github.com/elastic/kibana/issues/171666
+ // FLAKY: https://github.com/elastic/kibana/issues/171666
describe.skip('Endpoint `execute` response action', function () {
targetTags(this, ['@ess', '@serverless']);
From 80b755ad6511aa19ea1f4e4bb618c52dcf13ea6c Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:25:41 +0000
Subject: [PATCH 19/95] skip flaky suite (#171667)
---
.../apis/endpoint_response_actions/execute.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
index 1da78f53b3627..401ff25fee620 100644
--- a/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
+++ b/x-pack/test/security_solution_endpoint_api_int/apis/endpoint_response_actions/execute.ts
@@ -17,6 +17,7 @@ export default function ({ getService }: FtrProviderContext) {
const endpointTestResources = getService('endpointTestResources');
// FLAKY: https://github.com/elastic/kibana/issues/171666
+ // FLAKY: https://github.com/elastic/kibana/issues/171667
describe.skip('Endpoint `execute` response action', function () {
targetTags(this, ['@ess', '@serverless']);
From 304b4a35be889eacb78d0230fab5495a6a7de5b7 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:27:56 +0000
Subject: [PATCH 20/95] skip flaky suite (#173670)
---
.../security_solution_endpoint/apps/endpoint/endpoint_list.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
index 0f65111b81e5b..d0267b3eac5ac 100644
--- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
@@ -86,6 +86,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
};
// Flaky: https://github.com/elastic/kibana/issues/170357
+ // FLAKY: https://github.com/elastic/kibana/issues/173670
describe.skip('endpoint list', function () {
targetTags(this, ['@ess', '@serverless']);
From 4b8edd785ddc2e0dd1d310b96187aee15686fb75 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:29:02 +0000
Subject: [PATCH 21/95] skip flaky suite (#170357)
---
.../security_solution_endpoint/apps/endpoint/endpoint_list.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
index d0267b3eac5ac..e4d9b91e579b7 100644
--- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts
@@ -85,7 +85,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
return tableData;
};
- // Flaky: https://github.com/elastic/kibana/issues/170357
+ // FLAKY: https://github.com/elastic/kibana/issues/170357
// FLAKY: https://github.com/elastic/kibana/issues/173670
describe.skip('endpoint list', function () {
targetTags(this, ['@ess', '@serverless']);
From 3d4aaba1956f40fcab38d919ef7121fa3ff3c83c Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:33:01 +0000
Subject: [PATCH 22/95] skip flaky suite (#168904)
---
.../ftr/cloud_security_posture/compliance_dashboard.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/compliance_dashboard.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/compliance_dashboard.ts
index 54fa5a725e29a..6a6734b8f3fe3 100644
--- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/compliance_dashboard.ts
+++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/compliance_dashboard.ts
@@ -56,7 +56,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await pageObjects.svlCommonPage.forceLogout();
});
- describe('Kubernetes Dashboard', () => {
+ // FLAKY: https://github.com/elastic/kibana/issues/168904
+ describe.skip('Kubernetes Dashboard', () => {
it('displays accurate summary compliance score', async () => {
const scoreElement = await dashboard.getKubernetesComplianceScore();
From 6825c02faf409a01404729e1ba63453a3cf93aa6 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:40:55 +0000
Subject: [PATCH 23/95] skip flaky suite (#173597)
---
.../e2e/investigations/alerts/changing_alert_status.cy.ts | 1 +
1 file changed, 1 insertion(+)
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 e8426c4599fb5..8a49b4eb02065 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
@@ -158,6 +158,7 @@ describe('Changing alert status', { tags: ['@ess', '@brokenInServerless'] }, ()
});
});
});
+ // FLAKY: https://github.com/elastic/kibana/issues/173597
context.skip('Closing alerts', () => {
beforeEach(() => {
login();
From 3fbf0ddf1dc6feac3b407b0b7f3795b9ebf913ca Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:42:56 +0000
Subject: [PATCH 24/95] skip flaky suite (#173586)
---
test/functional/apps/discover/group1/_discover_histogram.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/functional/apps/discover/group1/_discover_histogram.ts b/test/functional/apps/discover/group1/_discover_histogram.ts
index 43f39b417864c..bdaf14fca96e4 100644
--- a/test/functional/apps/discover/group1/_discover_histogram.ts
+++ b/test/functional/apps/discover/group1/_discover_histogram.ts
@@ -33,7 +33,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const log = getService('log');
const queryBar = getService('queryBar');
- describe('discover histogram', function describeIndexTests() {
+ // FLAKY: https://github.com/elastic/kibana/issues/173586
+ describe.skip('discover histogram', function describeIndexTests() {
before(async () => {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
await esArchiver.load('test/functional/fixtures/es_archiver/long_window_logstash');
From e2c8db12d02e867037833a830f004f69088245a9 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:44:08 +0000
Subject: [PATCH 25/95] skip flaky suite (#173625)
---
.../apps/management/data_views/_data_view_create_delete.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/functional/apps/management/data_views/_data_view_create_delete.ts b/test/functional/apps/management/data_views/_data_view_create_delete.ts
index e3bc2240887ad..245ac88606b50 100644
--- a/test/functional/apps/management/data_views/_data_view_create_delete.ts
+++ b/test/functional/apps/management/data_views/_data_view_create_delete.ts
@@ -187,7 +187,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
});
- describe('index pattern edit', function () {
+ // FLAKY: https://github.com/elastic/kibana/issues/173625
+ describe.skip('index pattern edit', function () {
it('should update field list', async function () {
await PageObjects.settings.editIndexPattern(
'kibana_sample_data_flights',
From 1e1d959010c38d877bab0edc9e951263d2a96702 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 17:46:55 +0000
Subject: [PATCH 26/95] skip flaky suite (#173653)
---
.../test_suites/observability/burn_rate_rule/burn_rate_rule.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/burn_rate_rule/burn_rate_rule.ts b/x-pack/test_serverless/api_integration/test_suites/observability/burn_rate_rule/burn_rate_rule.ts
index 7d863d6cdbc66..0d2f3a5958d47 100644
--- a/x-pack/test_serverless/api_integration/test_suites/observability/burn_rate_rule/burn_rate_rule.ts
+++ b/x-pack/test_serverless/api_integration/test_suites/observability/burn_rate_rule/burn_rate_rule.ts
@@ -70,7 +70,8 @@ export default function ({ getService }: FtrProviderContext) {
await cleanup({ esClient, logger });
});
- describe('Rule creation', () => {
+ // FLAKY: https://github.com/elastic/kibana/issues/173653
+ describe.skip('Rule creation', () => {
it('creates rule successfully', async () => {
actionId = await alertingApi.createIndexConnector({
name: 'Index Connector: Slo Burn rate API test',
From b26bd788e794717c514a998a722c5e5150643b4d Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 18:48:09 +0000
Subject: [PATCH 27/95] skip flaky suite (#173681)
---
.../apps/integrations/artifact_entries_list.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
index 802cbf8be16fc..9dd9b319071a4 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
@@ -51,7 +51,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
.set('kbn-xsrf', 'true');
};
- describe('For each artifact list under management', function () {
+ // FLAKY: https://github.com/elastic/kibana/issues/173681
+ describe.skip('For each artifact list under management', function () {
targetTags(this, ['@ess', '@serverless']);
this.timeout(60_000 * 5);
From 182b2c95c0fe3e714ffca0e4ab8c2b76f81604ed Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 18:49:46 +0000
Subject: [PATCH 28/95] skip flaky suite (#173682)
---
.../apps/integrations/artifact_entries_list.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
index 9dd9b319071a4..5746a9cc06a25 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
@@ -52,6 +52,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
};
// FLAKY: https://github.com/elastic/kibana/issues/173681
+ // FLAKY: https://github.com/elastic/kibana/issues/173682
describe.skip('For each artifact list under management', function () {
targetTags(this, ['@ess', '@serverless']);
From dd765ab84c98ddd823dc48152c36bc7ee6a1bd81 Mon Sep 17 00:00:00 2001
From: Robert Austin
Date: Tue, 19 Dec 2023 14:13:12 -0500
Subject: [PATCH 29/95] Allow members of @security-solution-test-skippers to
use `/skip` comments on failed test issues (#173430)
## Summary
After a PR is merged, CI runs all the tests on `main`. If one fails, a
github issue with the label `failed-test` is created. If you comment
`/skip` on the issue then a workflow action will skip the test directly
on the failing branches.
This workflow can only be used by contributors who have `admin` access
to Kibana, OR to people who are on an allow-list of elastic teams. The
list of teams allowed is `appex-qa`.
This PR adds another team to the list:
@elastic/security-solution-test-skippers
This team was just created to allow a small list of Security Solution
contributors the ability to use this workflow.
Allowing a few of us access to this workflow will allow Security to
triage our own test by writing `/skip` comments.
### Without this PR we have to:
Without this PR we have to do a bunch of stuff to skip our own flaky
tests:
1. Manually edit the files to create a PR on all affected branches.
2. Create PRs using the web app.
3. Get a second developer to approve the PR.
4. Wait for CI.
5. Merge the PR.
This process is slow because of manual steps, and because CI must run
before we can skip the test. At a minimum we should expect that process
to take as long as CI takes (e.g. 90 minutes.) But the PRs that are
meant to skip tests may also in turn be blocked by flaky tests. It also
requires coordination from 2 people to make and approve the PR.
### Code references
[skip-failed-test.yml](https://github.com/elastic/kibana/blob/main/.github/workflows/skip-failed-test.yml#L25-L30)
is where the workflow is defined
[Docs on the syntax for
workflows.](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses)
[permission-check/index.ts](https://github.com/elastic/kibana-github-actions/blob/main/permission-check/index.ts#L23-L26)
is where the permission check is implemented. Users need to have:
* either the right permission level
* or be a member of the team
### Checklist
Delete any items that are not applicable to this PR.
- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
### Risk Matrix
Delete this section if it is not applicable to this PR.
Before closing this PR, invite QA, stakeholders, and other developers to
identify risks that should be tested prior to the change/feature
release.
When forming the risk matrix, consider some of the following examples
and how they may potentially impact the change:
| Risk | Probability | Severity | Mitigation/Notes |
|---------------------------|-------------|----------|-------------------------|
| Multiple Spaces—unexpected behavior in non-default Kibana Space.
| Low | High | Integration tests will verify that all features are still
supported in non-default Kibana Space and when user switches between
spaces. |
| Multiple nodes—Elasticsearch polling might have race conditions
when multiple Kibana nodes are polling for the same tasks. | High | Low
| Tasks are idempotent, so executing them multiple times will not result
in logical error, but will degrade performance. To test for this case we
add plenty of unit tests around this logic and document manual testing
procedure. |
| Code should gracefully handle cases when feature X or plugin Y are
disabled. | Medium | High | Unit tests will verify that any feature flag
or plugin combination still results in our service operational. |
| [See more potential risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) |
### For maintainers
- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
Co-authored-by: Gloria Hornero
---
.github/workflows/skip-failed-test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/skip-failed-test.yml b/.github/workflows/skip-failed-test.yml
index 9ac9485709bd6..039d0ab8aa8b4 100644
--- a/.github/workflows/skip-failed-test.yml
+++ b/.github/workflows/skip-failed-test.yml
@@ -26,7 +26,7 @@ jobs:
uses: ./actions/permission-check
with:
permission: admin
- teams: appex-qa
+ teams: appex-qa, security-solution-test-skippers
token: ${{secrets.KIBANAMACHINE_TOKEN}}
- name: Checkout kibana-operations
From cb06324f284470d948e4d28bbaea4d0069bc8a1f Mon Sep 17 00:00:00 2001
From: Kevin Logan <56395104+kevinlog@users.noreply.github.com>
Date: Tue, 19 Dec 2023 14:16:26 -0500
Subject: [PATCH 30/95] [Security Solution] Skip failing test (#173683)
## Summary
Skipping test that looks flaky after package change
### Checklist
Delete any items that are not applicable to this PR.
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
Co-authored-by: Tiago Costa
---
.../apps/integrations/artifact_entries_list.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
index 5746a9cc06a25..af8c246451d3f 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
@@ -50,7 +50,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
.delete(`${EXCEPTION_LIST_URL}?list_id=${listId}&namespace_type=agnostic`)
.set('kbn-xsrf', 'true');
};
-
+
+ // Flaky: https://github.com/elastic/kibana/issues/173682
// FLAKY: https://github.com/elastic/kibana/issues/173681
// FLAKY: https://github.com/elastic/kibana/issues/173682
describe.skip('For each artifact list under management', function () {
From 557f1c41c0e7b3fd9cde81d7628d4aeba8186441 Mon Sep 17 00:00:00 2001
From: Tiago Costa
Date: Tue, 19 Dec 2023 19:41:01 +0000
Subject: [PATCH 31/95] chore(NA): eslint fix
---
.../apps/integrations/artifact_entries_list.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
index af8c246451d3f..e7c58f6f27e6a 100644
--- a/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
+++ b/x-pack/test/security_solution_endpoint/apps/integrations/artifact_entries_list.ts
@@ -50,7 +50,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
.delete(`${EXCEPTION_LIST_URL}?list_id=${listId}&namespace_type=agnostic`)
.set('kbn-xsrf', 'true');
};
-
+
// Flaky: https://github.com/elastic/kibana/issues/173682
// FLAKY: https://github.com/elastic/kibana/issues/173681
// FLAKY: https://github.com/elastic/kibana/issues/173682
From b247e892be2da3307ad15ff3016571e1497ed0ab Mon Sep 17 00:00:00 2001
From: Kevin Delemme
Date: Tue, 19 Dec 2023 15:54:45 -0500
Subject: [PATCH 32/95] feat(slo): Add groupBy and instanceId in filter when
redirecting to apm (#173556)
---
.../components/error_budget_chart_panel.tsx | 33 +++++++
.../slo_details/components/header_control.tsx | 46 ++++-----
.../overview/apm_indicator_overview.tsx | 35 ++++---
.../components/overview/overview.tsx | 2 +-
.../badges/slo_indicator_type_badge.tsx | 39 +++-----
...apm_params_to_apm_app_deeplink_url.test.ts | 96 +++++++++++--------
..._sli_apm_params_to_apm_app_deeplink_url.ts | 46 +++++----
.../public/utils/slo/indicator.ts | 11 ++-
8 files changed, 173 insertions(+), 135 deletions(-)
diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/error_budget_chart_panel.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/error_budget_chart_panel.tsx
index b460e3e2a9423..a053e39fae34c 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/components/error_budget_chart_panel.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/components/error_budget_chart_panel.tsx
@@ -10,6 +10,7 @@ import numeral from '@elastic/numeral';
import { i18n } from '@kbn/i18n';
import { rollingTimeWindowTypeSchema, SLOWithSummaryResponse } from '@kbn/slo-schema';
import React from 'react';
+import { toDuration, toMinutes } from '../../../utils/slo/duration';
import { ChartData } from '../../../typings/slo';
import { useKibana } from '../../../utils/kibana_react';
import { toDurationAdverbLabel, toDurationLabel } from '../../../utils/slo/labels';
@@ -27,6 +28,24 @@ export function ErrorBudgetChartPanel({ data, isLoading, slo }: Props) {
const isSloFailed = slo.summary.status === 'DEGRADING' || slo.summary.status === 'VIOLATED';
+ let remainingBudgetFormatted;
+ if (slo.budgetingMethod === 'timeslices' && slo.timeWindow.type === 'calendarAligned') {
+ const totalSlices =
+ toMinutes(toDuration(slo.timeWindow.duration)) /
+ toMinutes(toDuration(slo.objective.timesliceWindow!));
+ const remainingBudgetInTimeUnit =
+ slo.summary.errorBudget.remaining * (slo.summary.errorBudget.initial * totalSlices);
+
+ if (remainingBudgetInTimeUnit <= 0) {
+ remainingBudgetFormatted = '0min';
+ } else {
+ if (remainingBudgetInTimeUnit / 60 >= 1) {
+ remainingBudgetFormatted = `${Math.trunc(remainingBudgetInTimeUnit / 60)}h`;
+ }
+ remainingBudgetFormatted += `${Math.trunc(remainingBudgetInTimeUnit % 60)}min`;
+ }
+ }
+
return (
@@ -68,6 +87,20 @@ export function ErrorBudgetChartPanel({ data, isLoading, slo }: Props) {
reverse
/>
+ {!!remainingBudgetFormatted && (
+
+
+
+ )}
diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
index 34eb1f278e7a3..b8bad5b98c4c5 100644
--- a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
+++ b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx
@@ -5,22 +5,22 @@
* 2.0.
*/
-import React, { useCallback, useState } from 'react';
-import { i18n } from '@kbn/i18n';
import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import { SLOWithSummaryResponse } from '@kbn/slo-schema';
+import React, { useCallback, useState } from 'react';
-import { useCloneSlo } from '../../../hooks/slo/use_clone_slo';
+import { rulesLocatorID, sloFeatureId } from '../../../../common';
+import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../common/constants';
+import { paths } from '../../../../common/locators/paths';
import { SloDeleteConfirmationModal } from '../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal';
import { useCapabilities } from '../../../hooks/slo/use_capabilities';
-import { useKibana } from '../../../utils/kibana_react';
+import { useCloneSlo } from '../../../hooks/slo/use_clone_slo';
import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo';
-import { isApmIndicatorType } from '../../../utils/slo/indicator';
-import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url';
-import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../common/constants';
-import { rulesLocatorID, sloFeatureId } from '../../../../common';
-import { paths } from '../../../../common/locators/paths';
import type { RulesParams } from '../../../locators/rules';
+import { useKibana } from '../../../utils/kibana_react';
+import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url';
+import { isApmIndicatorType } from '../../../utils/slo/indicator';
export interface Props {
slo: SLOWithSummaryResponse | undefined;
@@ -72,27 +72,13 @@ export function HeaderControl({ isLoading, slo }: Props) {
};
const handleNavigateToApm = () => {
- if (
- slo?.indicator.type === 'sli.apm.transactionDuration' ||
- slo?.indicator.type === 'sli.apm.transactionErrorRate'
- ) {
- const {
- indicator: {
- params: { environment, filter, service, transactionName, transactionType },
- },
- timeWindow: { duration },
- } = slo;
-
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- duration,
- environment,
- filter,
- service,
- transactionName,
- transactionType,
- });
+ if (!slo) {
+ return undefined;
+ }
- navigate(basePath.prepend(url));
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(slo);
+ if (url) {
+ navigateToUrl(basePath.prepend(url));
}
};
@@ -189,7 +175,7 @@ export function HeaderControl({ isLoading, slo }: Props) {
,
]
.concat(
- !!slo && isApmIndicatorType(slo.indicator.type) ? (
+ !!slo && isApmIndicatorType(slo.indicator) ? (
;
+ IndicatorOverview = ;
break;
}
diff --git a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
index 316298cd8d44c..60fceb4481b91 100644
--- a/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
+++ b/x-pack/plugins/observability/public/pages/slos/components/badges/slo_indicator_type_badge.tsx
@@ -5,14 +5,18 @@
* 2.0.
*/
-import React from 'react';
-import { EuiBadge, EuiFlexItem, EuiToolTip, EuiBadgeProps } from '@elastic/eui';
-import { SLOResponse, SLOWithSummaryResponse } from '@kbn/slo-schema';
-import { euiLightVars } from '@kbn/ui-theme';
+import { EuiBadge, EuiBadgeProps, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import {
+ apmTransactionDurationIndicatorSchema,
+ apmTransactionErrorRateIndicatorSchema,
+ SLOResponse,
+ SLOWithSummaryResponse,
+} from '@kbn/slo-schema';
+import { euiLightVars } from '@kbn/ui-theme';
+import React from 'react';
import { useKibana } from '../../../../utils/kibana_react';
import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url';
-import { isApmIndicatorType } from '../../../../utils/slo/indicator';
import { toIndicatorTypeLabel } from '../../../../utils/slo/labels';
export interface Props {
@@ -27,26 +31,8 @@ export function SloIndicatorTypeBadge({ slo, color }: Props) {
} = useKibana().services;
const handleNavigateToApm = () => {
- if (
- slo.indicator.type === 'sli.apm.transactionDuration' ||
- slo.indicator.type === 'sli.apm.transactionErrorRate'
- ) {
- const {
- indicator: {
- params: { environment, filter, service, transactionName, transactionType },
- },
- timeWindow: { duration },
- } = slo;
-
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- duration,
- environment,
- filter,
- service,
- transactionName,
- transactionType,
- });
-
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(slo);
+ if (url) {
navigateToUrl(basePath.prepend(url));
}
};
@@ -58,7 +44,8 @@ export function SloIndicatorTypeBadge({ slo, color }: Props) {
{toIndicatorTypeLabel(slo.indicator.type)}
- {isApmIndicatorType(slo.indicator.type) && 'service' in slo.indicator.params && (
+ {(apmTransactionDurationIndicatorSchema.is(slo.indicator) ||
+ apmTransactionErrorRateIndicatorSchema.is(slo.indicator)) && (
{
it('should return a correct APM deeplink when all params have a value', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl(SLI_APM_PARAMS);
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator(DEFAULT_PARAMS),
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30-d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
);
});
- it('should return a correct APM deeplink when empty duration is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- duration: '',
- });
+ it('should return a correct APM deeplink when all environment is passed', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator({ ...DEFAULT_PARAMS, environment: ALL_VALUE }),
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=ENVIRONMENT_ALL&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
);
});
- it('should return a correct APM deeplink when empty environment is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- environment: '',
- });
+ it('should return a correct APM deeplink when empty filter is passed', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator({ ...DEFAULT_PARAMS, filter: '' }),
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&transactionType=blarfType&rangeFrom=now-30-d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22"`
);
});
- it('should return a correct APM deeplink when empty filter is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- filter: '',
- });
+ it('should return an empty string if all service is passed', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator({ ...DEFAULT_PARAMS, service: ALL_VALUE }),
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30-d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22"`
+ `"/app/apm/services/*/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
);
});
- it('should return an empty string if an empty service is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- service: '',
- });
+ it('should return a correct APM deeplink when all transactionName is passed', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator({ ...DEFAULT_PARAMS, transactionName: ALL_VALUE }),
+ })
+ );
- expect(url).toMatchInlineSnapshot(`""`);
+ expect(url).toMatchInlineSnapshot(
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ );
});
- it('should return a correct APM deeplink when empty transactionName is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- transactionName: '',
- });
+ it('should return a correct APM deeplink when all transactionType is passed', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator({ ...DEFAULT_PARAMS, transactionType: ALL_VALUE }),
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30-d&rangeTo=now&kuery=agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
);
});
- it('should return a correct APM deeplink when empty transactionType is passed', () => {
- const url = convertSliApmParamsToApmAppDeeplinkUrl({
- ...SLI_APM_PARAMS,
- transactionType: '',
- });
+ it('should return a correct APM deeplink when groupBy and instanceId are provided', () => {
+ const url = convertSliApmParamsToApmAppDeeplinkUrl(
+ buildSlo({
+ indicator: buildApmLatencyIndicator(DEFAULT_PARAMS),
+ groupBy: 'label.project_id',
+ instanceId: 'bf6689b383749812f35c7a408f57d113',
+ })
+ );
expect(url).toMatchInlineSnapshot(
- `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&rangeFrom=now-30-d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12+"`
+ `"/app/apm/services/barService/overview?comparisonEnabled=true&environment=fooEnvironment&transactionType=blarfType&rangeFrom=now-30d&rangeTo=now&kuery=transaction.name+%3A+%22bazName%22+and+agent.name+%3A+%22beats%22+and+agent.version+%3A+3.4.12++and+label.project_id+%3A+%22bf6689b383749812f35c7a408f57d113%22"`
);
});
});
diff --git a/x-pack/plugins/observability/public/utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url.ts b/x-pack/plugins/observability/public/utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url.ts
index a36a6f8c70b28..4cf2f8865233b 100644
--- a/x-pack/plugins/observability/public/utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url.ts
+++ b/x-pack/plugins/observability/public/utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url.ts
@@ -5,29 +5,30 @@
* 2.0.
*/
-import { ALL_VALUE } from '@kbn/slo-schema';
-
-interface Props {
- duration?: string;
- environment: string;
- filter: string | undefined;
- service: string;
- transactionName: string;
- transactionType: string;
-}
-
-export function convertSliApmParamsToApmAppDeeplinkUrl({
- duration,
- environment,
- filter,
- service,
- transactionName,
- transactionType,
-}: Props) {
- if (!service) {
- return '';
+import {
+ ALL_VALUE,
+ apmTransactionDurationIndicatorSchema,
+ apmTransactionErrorRateIndicatorSchema,
+ SLOResponse,
+} from '@kbn/slo-schema';
+
+export function convertSliApmParamsToApmAppDeeplinkUrl(slo: SLOResponse): string | undefined {
+ if (
+ !apmTransactionDurationIndicatorSchema.is(slo.indicator) &&
+ !apmTransactionErrorRateIndicatorSchema.is(slo.indicator)
+ ) {
+ return undefined;
}
+ const {
+ indicator: {
+ params: { environment, filter, service, transactionName, transactionType },
+ },
+ timeWindow: { duration },
+ groupBy,
+ instanceId,
+ } = slo;
+
const qs = new URLSearchParams('comparisonEnabled=true');
if (environment) {
@@ -50,6 +51,9 @@ export function convertSliApmParamsToApmAppDeeplinkUrl({
if (filter && filter.length > 0) {
kueryParams.push(filter);
}
+ if (groupBy !== ALL_VALUE && instanceId !== ALL_VALUE) {
+ kueryParams.push(`${groupBy} : "${instanceId}"`);
+ }
if (kueryParams.length > 0) {
qs.append('kuery', kueryParams.join(' and '));
diff --git a/x-pack/plugins/observability/public/utils/slo/indicator.ts b/x-pack/plugins/observability/public/utils/slo/indicator.ts
index 955eab9e33299..ece808ddc033f 100644
--- a/x-pack/plugins/observability/public/utils/slo/indicator.ts
+++ b/x-pack/plugins/observability/public/utils/slo/indicator.ts
@@ -5,7 +5,12 @@
* 2.0.
*/
-import { SLOWithSummaryResponse } from '@kbn/slo-schema';
+import {
+ apmTransactionDurationIndicatorSchema,
+ apmTransactionErrorRateIndicatorSchema,
+ Indicator,
+} from '@kbn/slo-schema';
-export const isApmIndicatorType = (indicatorType: SLOWithSummaryResponse['indicator']['type']) =>
- ['sli.apm.transactionDuration', 'sli.apm.transactionErrorRate'].includes(indicatorType);
+export const isApmIndicatorType = (indicator: Indicator): boolean =>
+ apmTransactionDurationIndicatorSchema.is(indicator) ||
+ apmTransactionErrorRateIndicatorSchema.is(indicator);
From 641177e2fed06a4c4d44eb6ba8e2bea2310f5404 Mon Sep 17 00:00:00 2001
From: Adam Demjen
Date: Tue, 19 Dec 2023 17:37:29 -0500
Subject: [PATCH 33/95] [Enterprise Search] Split details panel from model
selection list (#173434)
## Summary
In this PR the ML model selection list is being split into a simplified
list and a details panel for the selected model. This change provides
problem-free keyboard navigation and a cleaner look.
The Start button in the model panel now appears and works for any model,
not just ELSER/E5.
In order to make the model status labels and actions consistent, some
labels have been renamed:
- "Downloaded" -> "Deployed"
- "Downloading" -> "Deploying"
The fetch logic is now returning "Not deployed" for a downloaded curated
model. Any model (curated or 3rd party) in this state can be started
with the Start button.
### Checklist
Delete any items that are not applicable to this PR.
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
---
.../ml_inference/configure_pipeline.tsx | 31 +-
.../ml_inference/license_badge.test.tsx | 35 ++
.../pipelines/ml_inference/license_badge.tsx | 41 ++
.../ml_inference/ml_inference_logic.ts | 2 +-
.../ml_inference/model_select.test.tsx | 101 ++++-
.../pipelines/ml_inference/model_select.tsx | 358 ++++++++++++++++--
.../ml_inference/model_select_logic.ts | 56 ++-
.../ml_inference/model_select_option.test.tsx | 53 +--
.../ml_inference/model_select_option.tsx | 236 ++----------
.../pipelines/ml_model_health.test.tsx | 12 +-
.../pipelines/ml_model_health.tsx | 28 +-
.../server/lib/ml/fetch_ml_models.test.ts | 2 +-
.../server/lib/ml/fetch_ml_models.ts | 4 +-
13 files changed, 614 insertions(+), 345 deletions(-)
create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.test.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx
index 52d4f38b45408..cc318831555af 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/configure_pipeline.tsx
@@ -19,7 +19,6 @@ import {
EuiTabbedContentTab,
EuiTitle,
EuiText,
- EuiTextColor,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -131,27 +130,15 @@ export const ConfigurePipeline: React.FC = () => {
>
)}
-
-
-
- {i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.addInferencePipelineModal.steps.configure.titleSelectTrainedModel',
- { defaultMessage: 'Select a trained ML Model' }
- )}
-
-
- {formErrors.modelStatus !== undefined && (
- <>
-
-
-
- {formErrors.modelStatus}
-
-
- >
- )}
-
-
+
+
+
>
),
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.test.tsx
new file mode 100644
index 0000000000000..dcb67572783e1
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.test.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+
+import { shallow } from 'enzyme';
+
+import { EuiLink } from '@elastic/eui';
+
+import { LicenseBadge, LicenseBadgeProps } from './license_badge';
+
+const DEFAULT_PROPS: LicenseBadgeProps = {
+ licenseType: 'mit',
+ modelDetailsPageUrl: 'https://my-model.ai',
+};
+
+describe('LicenseBadge', () => {
+ it('renders with link if URL is present', () => {
+ const wrapper = shallow(
+
+ );
+ expect(wrapper.find(EuiLink)).toHaveLength(1);
+ });
+ it('renders without link if URL is not present', () => {
+ const wrapper = shallow();
+ expect(wrapper.find(EuiLink)).toHaveLength(0);
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.tsx
new file mode 100644
index 0000000000000..414cbdf3057ca
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/license_badge.tsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+
+import { EuiBadge, EuiLink } from '@elastic/eui';
+
+import { i18n } from '@kbn/i18n';
+
+export interface LicenseBadgeProps {
+ licenseType: string;
+ modelDetailsPageUrl?: string;
+}
+
+export const LicenseBadge: React.FC = ({ licenseType, modelDetailsPageUrl }) => {
+ const licenseLabel = i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.licenseBadge.label',
+ {
+ defaultMessage: 'License: {licenseType}',
+ values: {
+ licenseType,
+ },
+ }
+ );
+
+ return (
+
+ {modelDetailsPageUrl ? (
+
+ {licenseLabel}
+
+ ) : (
+ {licenseLabel}
+ )}
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts
index dd01db93bd689..407f33eb1e2d0 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/ml_inference_logic.ts
@@ -119,7 +119,7 @@ export interface MLInferencePipelineOption {
indexFields: string[];
}
-interface MLInferenceProcessorsActions {
+export interface MLInferenceProcessorsActions {
addSelectedFieldsToMapping: (isTextExpansionModelSelected: boolean) => {
isTextExpansionModelSelected: boolean;
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx
index 9bd006f65883e..f82c0ffb3b1c8 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.test.tsx
@@ -11,13 +11,23 @@ import React from 'react';
import { shallow } from 'enzyme';
-import { EuiSelectable } from '@elastic/eui';
+import { EuiSelectable, EuiText } from '@elastic/eui';
-import { ModelSelect } from './model_select';
+import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml';
+
+import { LicenseBadge } from './license_badge';
+import {
+ DeployModelButton,
+ ModelSelect,
+ NoModelSelected,
+ SelectedModel,
+ StartModelButton,
+} from './model_select';
const DEFAULT_VALUES = {
addInferencePipelineModal: {
configuration: {},
+ indexName: 'my-index',
},
selectableModels: [
{
@@ -27,8 +37,23 @@ const DEFAULT_VALUES = {
modelId: 'model_2',
},
],
- indexName: 'my-index',
};
+const DEFAULT_MODEL: MlModel = {
+ modelId: 'model_1',
+ type: 'ner',
+ title: 'Model 1',
+ description: 'Model 1 description',
+ licenseType: 'elastic',
+ modelDetailsPageUrl: 'https://my-model.ai',
+ deploymentState: MlModelDeploymentState.NotDeployed,
+ startTime: 0,
+ targetAllocationCount: 0,
+ nodeAllocationCount: 0,
+ threadsPerAllocation: 0,
+ isPlaceholder: false,
+ hasStats: false,
+};
+
const MOCK_ACTIONS = {
setInferencePipelineConfiguration: jest.fn(),
};
@@ -150,4 +175,74 @@ describe('ModelSelect', () => {
})
);
});
+ it('renders selected model panel if a model is selected', () => {
+ setMockValues({
+ ...DEFAULT_VALUES,
+ addInferencePipelineModal: {
+ configuration: {
+ ...DEFAULT_VALUES.addInferencePipelineModal.configuration,
+ modelID: 'model_2',
+ },
+ },
+ selectedModel: DEFAULT_MODEL,
+ });
+
+ const wrapper = shallow();
+ expect(wrapper.find(SelectedModel)).toHaveLength(1);
+ expect(wrapper.find(NoModelSelected)).toHaveLength(0);
+ });
+ it('renders no model selected panel if no model is selected', () => {
+ setMockValues(DEFAULT_VALUES);
+
+ const wrapper = shallow();
+ expect(wrapper.find(SelectedModel)).toHaveLength(0);
+ expect(wrapper.find(NoModelSelected)).toHaveLength(1);
+ });
+
+ describe('SelectedModel', () => {
+ it('renders with license badge if present', () => {
+ const wrapper = shallow();
+ expect(wrapper.find(LicenseBadge)).toHaveLength(1);
+ });
+ it('renders without license badge if not present', () => {
+ const props = {
+ ...DEFAULT_MODEL,
+ licenseType: undefined,
+ };
+
+ const wrapper = shallow();
+ expect(wrapper.find(LicenseBadge)).toHaveLength(0);
+ });
+ it('renders with description if present', () => {
+ const wrapper = shallow();
+ expect(wrapper.find(EuiText)).toHaveLength(1);
+ });
+ it('renders without description if not present', () => {
+ const props = {
+ ...DEFAULT_MODEL,
+ description: undefined,
+ };
+
+ const wrapper = shallow();
+ expect(wrapper.find(EuiText)).toHaveLength(0);
+ });
+ it('renders deploy button for a model placeholder', () => {
+ const props = {
+ ...DEFAULT_MODEL,
+ isPlaceholder: true,
+ };
+
+ const wrapper = shallow();
+ expect(wrapper.find(DeployModelButton)).toHaveLength(1);
+ });
+ it('renders start button for a downloaded model', () => {
+ const props = {
+ ...DEFAULT_MODEL,
+ deploymentState: MlModelDeploymentState.NotDeployed,
+ };
+
+ const wrapper = shallow();
+ expect(wrapper.find(StartModelButton)).toHaveLength(1);
+ });
+ });
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx
index ac3900b6ed662..6f5fc424aef0b 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select.tsx
@@ -5,31 +5,297 @@
* 2.0.
*/
-import React from 'react';
+import React, { useState } from 'react';
import { useActions, useValues } from 'kea';
-import { EuiSelectable, useIsWithinMaxBreakpoint } from '@elastic/eui';
+import {
+ EuiButton,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiLoadingSpinner,
+ EuiPanel,
+ EuiScreenReaderLive,
+ EuiSelectable,
+ EuiText,
+ EuiTextColor,
+ EuiTitle,
+ useEuiTheme,
+ useIsWithinMaxBreakpoint,
+} from '@elastic/eui';
-import { MlModel } from '../../../../../../../common/types/ml';
-import { IndexNameLogic } from '../../index_name_logic';
-import { IndexViewLogic } from '../../index_view_logic';
+import { i18n } from '@kbn/i18n';
-import { MLInferenceLogic } from './ml_inference_logic';
+import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml';
+
+import { LicenseBadge } from './license_badge';
import { ModelSelectLogic } from './model_select_logic';
import { ModelSelectOption, ModelSelectOptionProps } from './model_select_option';
import { normalizeModelName } from './utils';
+export const DeployModelButton: React.FC<{
+ onClick: () => void;
+ modelId: string;
+ disabled: boolean;
+}> = ({ onClick, modelId, disabled }) => {
+ return (
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.deployButton.label',
+ {
+ defaultMessage: 'Deploy',
+ }
+ )}
+
+ );
+};
+
+export const ModelDeployingButton: React.FC = () => {
+ return (
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.deployingButton.label',
+ {
+ defaultMessage: 'Deploying',
+ }
+ )}
+
+
+
+ );
+};
+
+export const StartModelButton: React.FC<{
+ onClick: () => void;
+ modelId: string;
+ disabled: boolean;
+}> = ({ onClick, modelId, disabled }) => {
+ return (
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.startButton.label',
+ {
+ defaultMessage: 'Start',
+ }
+ )}
+
+ );
+};
+
+export const ModelStartingButton: React.FC = () => {
+ return (
+
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.startingButton.label',
+ {
+ defaultMessage: 'Starting',
+ }
+ )}
+
+
+
+ );
+};
+
+export const NoModelSelected: React.FC = () => (
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.noModelSelectedPanel.text',
+ { defaultMessage: 'Select an available model to add to your inference pipeline' }
+ )}
+
+
+);
+
+export const SelectedModel: React.FC = (model) => {
+ const { createModel, startModel } = useActions(ModelSelectLogic);
+ const { areActionButtonsDisabled } = useValues(ModelSelectLogic);
+
+ const getSelectedModelAnnouncement = (selectedModel: MlModel) =>
+ selectedModel.isPlaceholder
+ ? i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.selectedModelNotDeployedAnnouncement',
+ {
+ defaultMessage: '{modelId} model selected but not deployed',
+ values: {
+ modelId: selectedModel.modelId,
+ },
+ }
+ )
+ : selectedModel.deploymentState === MlModelDeploymentState.NotDeployed
+ ? i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.selectedModelNotStartedAnnouncement',
+ {
+ defaultMessage: '{modelId} model selected but not started',
+ values: {
+ modelId: selectedModel.modelId,
+ },
+ }
+ )
+ : i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.selectedModelAnnouncement',
+ {
+ defaultMessage: '{modelId} model selected',
+ values: {
+ modelId: selectedModel.modelId,
+ },
+ }
+ );
+
+ return (
+
+ {getSelectedModelAnnouncement(model)}
+
+
+
+
+ {model.title}
+
+
+
+ {model.modelId}
+
+ {model.description && (
+
+ {model.description}
+
+ )}
+ {model.licenseType && (
+
+ {/* Wrap in a span to prevent the badge from growing to a whole row on mobile */}
+
+
+
+
+ )}
+ {(model.isPlaceholder ||
+ [
+ MlModelDeploymentState.Downloading,
+ MlModelDeploymentState.NotDeployed,
+ MlModelDeploymentState.Starting,
+ ].includes(model.deploymentState)) && (
+ <>
+
+
+
+ {model.isPlaceholder ? (
+ <>
+
+ createModel(model.modelId)}
+ modelId={model.modelId}
+ disabled={areActionButtonsDisabled}
+ />
+
+
+
+
+
+ {i18n.translate(
+ 'xpack.enterpriseSearch.content.indices.pipelines.modelSelect.modelNotDeployedError',
+ { defaultMessage: 'Model must be deployed before use.' }
+ )}
+
+
+
+
+ >
+ ) : model.deploymentState === MlModelDeploymentState.Downloading ? (
+
+
+
+ ) : model.deploymentState === MlModelDeploymentState.NotDeployed ? (
+
+ startModel(model.modelId)}
+ modelId={model.modelId}
+ disabled={areActionButtonsDisabled}
+ />
+
+ ) : model.deploymentState === MlModelDeploymentState.Starting ? (
+
+
+
+ ) : (
+ <>>
+ )}
+
+
+ >
+ )}
+
+
+
+ );
+};
+
export const ModelSelect: React.FC = () => {
- const { indexName } = useValues(IndexNameLogic);
- const { ingestionMethod } = useValues(IndexViewLogic);
const {
- addInferencePipelineModal: { configuration },
- } = useValues(MLInferenceLogic);
- const { selectableModels, isLoading } = useValues(ModelSelectLogic);
- const { setInferencePipelineConfiguration } = useActions(MLInferenceLogic);
+ addInferencePipelineModal: { configuration, indexName },
+ ingestionMethod,
+ isLoading,
+ selectableModels,
+ selectedModel,
+ } = useValues(ModelSelectLogic);
+ const { setInferencePipelineConfiguration } = useActions(ModelSelectLogic);
+ const { euiTheme } = useEuiTheme();
const { modelID, pipelineName, isPipelineNameUserSupplied } = configuration;
+ const rowHeight = useIsWithinMaxBreakpoint('s') ? euiTheme.base * 8 : euiTheme.base * 6;
+ const maxVisibleOptions = 4.5;
+ const [listHeight, setListHeight] = useState(maxVisibleOptions * rowHeight);
const getModelSelectOptionProps = (models: MlModel[]): ModelSelectOptionProps[] =>
(models ?? []).map((model) => ({
@@ -39,44 +305,58 @@ export const ModelSelect: React.FC = () => {
}));
const onChange = (options: ModelSelectOptionProps[]) => {
- const selectedOption = options.find((option) => option.checked === 'on');
+ const selectedModelOption = options.find((option) => option.checked === 'on');
+
setInferencePipelineConfiguration({
...configuration,
inferenceConfig: undefined,
- modelID: selectedOption?.modelId ?? '',
- isModelPlaceholderSelected: selectedOption?.isPlaceholder ?? false,
+ modelID: selectedModelOption?.modelId ?? '',
+ isModelPlaceholderSelected: selectedModelOption?.isPlaceholder ?? false,
fieldMappings: undefined,
pipelineName: isPipelineNameUserSupplied
? pipelineName
- : indexName + '-' + normalizeModelName(selectedOption?.modelId ?? ''),
+ : indexName + '-' + normalizeModelName(selectedModelOption?.modelId ?? ''),
});
};
+ const onSearchChange = (_: string, matchingOptions: ModelSelectOptionProps[]) => {
+ setListHeight(Math.min(maxVisibleOptions, matchingOptions.length) * rowHeight);
+ };
+
const renderOption = (option: ModelSelectOptionProps) => ;
return (
-
- {(list, search) => (
- <>
- {search}
- {list}
- >
- )}
-
+
+
+
+ {(list, search) => (
+ <>
+ {search}
+ {list}
+ >
+ )}
+
+
+
+ {selectedModel ? : }
+
+
);
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts
index 5cfa2148203e1..6fe25cd3c8b5f 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_logic.ts
@@ -23,6 +23,13 @@ import {
StartModelApiLogic,
StartModelApiLogicActions,
} from '../../../../api/ml_models/start_model_api_logic';
+import { IndexViewLogic } from '../../index_view_logic';
+
+import {
+ MLInferenceLogic,
+ MLInferenceProcessorsActions,
+ MLInferenceProcessorsValues,
+} from './ml_inference_logic';
export interface ModelSelectActions {
createModel: (modelId: string) => { modelId: string };
@@ -40,18 +47,26 @@ export interface ModelSelectActions {
startModelError: CreateModelApiLogicActions['apiError'];
startModelMakeRequest: StartModelApiLogicActions['makeRequest'];
startModelSuccess: StartModelApiLogicActions['apiSuccess'];
+
+ setInferencePipelineConfiguration: MLInferenceProcessorsActions['setInferencePipelineConfiguration'];
+ setInferencePipelineConfigurationFromMLInferenceLogic: MLInferenceProcessorsActions['setInferencePipelineConfiguration'];
}
export interface ModelSelectValues {
+ addInferencePipelineModal: MLInferenceProcessorsValues['addInferencePipelineModal'];
+ addInferencePipelineModalFromMLInferenceLogic: MLInferenceProcessorsValues['addInferencePipelineModal'];
areActionButtonsDisabled: boolean;
createModelError: HttpError | undefined;
createModelStatus: Status;
+ ingestionMethod: string;
+ ingestionMethodFromIndexViewLogic: string;
isLoading: boolean;
isInitialLoading: boolean;
modelStateChangeError: string | undefined;
modelsData: FetchModelsApiResponse | undefined;
modelsStatus: Status;
selectableModels: MlModel[];
+ selectedModel: MlModel | undefined;
startModelError: HttpError | undefined;
startModelStatus: Status;
}
@@ -60,22 +75,27 @@ export const ModelSelectLogic = kea ({ modelId }),
fetchModels: true,
+ setInferencePipelineConfiguration: (configuration) => ({ configuration }),
startModel: (modelId: string) => ({ modelId }),
},
connect: {
actions: [
+ CachedFetchModelsApiLogic,
+ [
+ 'makeRequest as fetchModelsMakeRequest',
+ 'apiSuccess as fetchModelsSuccess',
+ 'apiError as fetchModelsError',
+ 'startPolling as startPollingModels',
+ ],
CreateModelApiLogic,
[
'makeRequest as createModelMakeRequest',
'apiSuccess as createModelSuccess',
'apiError as createModelError',
],
- CachedFetchModelsApiLogic,
+ MLInferenceLogic,
[
- 'makeRequest as fetchModelsMakeRequest',
- 'apiSuccess as fetchModelsSuccess',
- 'apiError as fetchModelsError',
- 'startPolling as startPollingModels',
+ 'setInferencePipelineConfiguration as setInferencePipelineConfigurationFromMLInferenceLogic',
],
StartModelApiLogic,
[
@@ -85,10 +105,14 @@ export const ModelSelectLogic = kea {
actions.startModelMakeRequest({ modelId });
},
+ setInferencePipelineConfiguration: ({ configuration }) => {
+ actions.setInferencePipelineConfigurationFromMLInferenceLogic(configuration);
+ },
startModelSuccess: () => {
actions.startPollingModels();
},
}),
path: ['enterprise_search', 'content', 'model_select_logic'],
selectors: ({ selectors }) => ({
+ addInferencePipelineModal: [
+ () => [selectors.addInferencePipelineModalFromMLInferenceLogic],
+ (modal) => modal, // Pass-through
+ ],
areActionButtonsDisabled: [
() => [selectors.createModelStatus, selectors.startModelStatus],
(createModelStatus: Status, startModelStatus: Status) =>
createModelStatus === Status.LOADING || startModelStatus === Status.LOADING,
],
+ ingestionMethod: [
+ () => [selectors.ingestionMethodFromIndexViewLogic],
+ (ingestionMethod) => ingestionMethod, // Pass-through
+ ],
modelStateChangeError: [
() => [selectors.createModelError, selectors.startModelError],
(createModelError?: HttpError, startModelError?: HttpError) => {
@@ -134,6 +169,13 @@ export const ModelSelectLogic = kea [selectors.modelsData],
(response: FetchModelsApiResponse) => response ?? [],
],
+ selectedModel: [
+ () => [selectors.selectableModels, selectors.addInferencePipelineModal],
+ (
+ models: MlModel[],
+ addInferencePipelineModal: MLInferenceProcessorsValues['addInferencePipelineModal']
+ ) => models.find((m) => m.modelId === addInferencePipelineModal.configuration.modelID),
+ ],
isLoading: [() => [selectors.isInitialLoading], (isInitialLoading) => isInitialLoading],
}),
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx
index 806366b7e652d..81d022aedfb74 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.test.tsx
@@ -11,19 +11,13 @@ import React from 'react';
import { shallow } from 'enzyme';
-import { EuiLink, EuiText } from '@elastic/eui';
+import { EuiText } from '@elastic/eui';
import { MlModelDeploymentState } from '../../../../../../../common/types/ml';
import { TrainedModelHealth } from '../ml_model_health';
-import {
- DeployModelButton,
- getContextMenuPanel,
- LicenseBadge,
- ModelSelectOption,
- ModelSelectOptionProps,
- StartModelButton,
-} from './model_select_option';
+import { LicenseBadge } from './license_badge';
+import { ModelSelectOption, ModelSelectOptionProps } from './model_select_option';
const DEFAULT_PROPS: ModelSelectOptionProps = {
modelId: 'model_1',
@@ -73,49 +67,8 @@ describe('ModelSelectOption', () => {
const wrapper = shallow();
expect(wrapper.find(EuiText)).toHaveLength(0);
});
- it('renders deploy button for a model placeholder', () => {
- const props = {
- ...DEFAULT_PROPS,
- isPlaceholder: true,
- };
-
- const wrapper = shallow();
- expect(wrapper.find(DeployModelButton)).toHaveLength(1);
- });
- it('renders start button for a downloaded model', () => {
- const props = {
- ...DEFAULT_PROPS,
- deploymentState: MlModelDeploymentState.Downloaded,
- };
-
- const wrapper = shallow();
- expect(wrapper.find(StartModelButton)).toHaveLength(1);
- });
it('renders status badge if there is no action button', () => {
const wrapper = shallow();
expect(wrapper.find(TrainedModelHealth)).toHaveLength(1);
});
});
-
-describe('LicenseBadge', () => {
- it('renders with link if URL is present', () => {
- const wrapper = shallow(
-
- );
- expect(wrapper.find(EuiLink)).toHaveLength(1);
- });
- it('renders without link if URL is not present', () => {
- const wrapper = shallow();
- expect(wrapper.find(EuiLink)).toHaveLength(0);
- });
-});
-
-describe('getContextMenuPanel', () => {
- it('gets model details link if URL is present', () => {
- const panels = getContextMenuPanel('https://model.ai');
- expect(panels[0].items).toHaveLength(2);
- });
-});
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx
index ebcf26210db39..ced26293cd68d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_inference/model_select_option.tsx
@@ -5,235 +5,68 @@
* 2.0.
*/
-import React, { useState } from 'react';
-
-import { useActions, useValues } from 'kea';
+import React from 'react';
import {
- EuiBadge,
- EuiButton,
- EuiButtonEmpty,
- EuiButtonIcon,
- EuiContextMenu,
- EuiContextMenuPanelDescriptor,
EuiFlexGroup,
EuiFlexItem,
- EuiLink,
- EuiPopover,
- EuiRadio,
EuiText,
EuiTextColor,
+ EuiTextTruncate,
EuiTitle,
useIsWithinMaxBreakpoint,
} from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-
-import { MlModel, MlModelDeploymentState } from '../../../../../../../common/types/ml';
-import { KibanaLogic } from '../../../../../shared/kibana';
+import { MlModel } from '../../../../../../../common/types/ml';
import { TrainedModelHealth } from '../ml_model_health';
-import { ModelSelectLogic } from './model_select_logic';
-import { TRAINED_MODELS_PATH } from './utils';
-
-export const getContextMenuPanel = (
- modelDetailsPageUrl?: string
-): EuiContextMenuPanelDescriptor[] => {
- return [
- {
- id: 0,
- items: [
- {
- name: i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.actionMenu.tuneModelPerformance.label',
- {
- defaultMessage: 'Tune model performance',
- }
- ),
- icon: 'controlsHorizontal',
- onClick: () =>
- KibanaLogic.values.navigateToUrl(TRAINED_MODELS_PATH, {
- shouldNotCreateHref: true,
- }),
- },
- ...(modelDetailsPageUrl
- ? [
- {
- name: i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.actionMenu.modelDetails.label',
- {
- defaultMessage: 'Model details',
- }
- ),
- icon: 'popout',
- href: modelDetailsPageUrl,
- target: '_blank',
- },
- ]
- : []),
- ],
- },
- ];
-};
+import { LicenseBadge } from './license_badge';
export type ModelSelectOptionProps = MlModel & {
label: string;
checked?: 'on';
};
-export const DeployModelButton: React.FC<{ onClick: () => void; disabled: boolean }> = ({
- onClick,
- disabled,
-}) => {
- return (
-
- {i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.deployButton.label',
- {
- defaultMessage: 'Deploy',
- }
- )}
-
- );
-};
-
-export const StartModelButton: React.FC<{ onClick: () => void; disabled: boolean }> = ({
- onClick,
- disabled,
-}) => {
- return (
-
- {i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.startButton.label',
- {
- defaultMessage: 'Start',
- }
- )}
-
- );
-};
-
-export const ModelMenuPopover: React.FC<{
- onClick: () => void;
- closePopover: () => void;
- isOpen: boolean;
- modelDetailsPageUrl?: string;
-}> = ({ onClick, closePopover, isOpen, modelDetailsPageUrl }) => {
- return (
-
- }
- isOpen={isOpen}
- closePopover={closePopover}
- anchorPosition="leftCenter"
- panelPaddingSize="none"
- >
-
-
- );
-};
-
-export interface LicenseBadgeProps {
- licenseType: string;
- modelDetailsPageUrl?: string;
-}
-
-export const LicenseBadge: React.FC = ({ licenseType, modelDetailsPageUrl }) => {
- const licenseLabel = i18n.translate(
- 'xpack.enterpriseSearch.content.indices.pipelines.modelSelectOption.licenseBadge.label',
- {
- defaultMessage: 'License: {licenseType}',
- values: {
- licenseType,
- },
- }
- );
-
- return (
-
- {modelDetailsPageUrl ? (
-
- {licenseLabel}
-
- ) : (
- {licenseLabel}
- )}
-
- );
-};
-
export const ModelSelectOption: React.FC = ({
modelId,
title,
description,
+ isPlaceholder,
licenseType,
- modelDetailsPageUrl,
deploymentState,
deploymentStateReason,
- isPlaceholder,
- checked,
}) => {
- const [isPopoverOpen, setIsPopoverOpen] = useState(false);
- const onMenuButtonClick = () => setIsPopoverOpen((isOpen) => !isOpen);
- const closePopover = () => setIsPopoverOpen(false);
-
- const { createModel, startModel } = useActions(ModelSelectLogic);
- const { areActionButtonsDisabled } = useValues(ModelSelectLogic);
-
return (
- {/* Selection radio button */}
-
- null}
- // @ts-ignore
- inert
- />
-
- {/* Title, model ID, description, license */}
- {title}
+
+
+
- {modelId}
+
+
+
{(licenseType || description) && (
{licenseType && (
- {/* Wrap in a div to prevent the badge from growing to a whole row on mobile */}
-
-
-
+ {/* Wrap in a span to prevent the badge from growing to a whole row on mobile */}
+
+
+
)}
{description && (
-
- {description}
-
+
)}
@@ -242,36 +75,15 @@ export const ModelSelectOption: React.FC = ({
)}
- {/* Status indicator OR action button */}
-
- {/* Wrap in a div to prevent the badge/button from growing to a whole row on mobile */}
-
- {isPlaceholder ? (
- createModel(modelId)}
- disabled={areActionButtonsDisabled}
- />
- ) : deploymentState === MlModelDeploymentState.Downloaded ? (
- startModel(modelId)}
- disabled={areActionButtonsDisabled}
- />
- ) : (
-
- )}
-
-
- {/* Actions menu */}
-
+ {/* Wrap in a span to prevent the badge from growing to a whole row on mobile */}
+
+
+
);
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx
index 65bfbc0951d30..c07c2dfc02958 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.test.tsx
@@ -34,13 +34,13 @@ describe('TrainedModelHealth', () => {
it('renders model downloading', () => {
const wrapper = shallow();
const health = wrapper.find(EuiHealth);
- expect(health.prop('children')).toEqual('Downloading');
+ expect(health.prop('children')).toEqual('Deploying');
expect(health.prop('color')).toEqual('warning');
});
it('renders model downloaded', () => {
const wrapper = shallow();
const health = wrapper.find(EuiHealth);
- expect(health.prop('children')).toEqual('Downloaded');
+ expect(health.prop('children')).toEqual('Deployed');
expect(health.prop('color')).toEqual('subdued');
});
it('renders model started', () => {
@@ -68,6 +68,14 @@ describe('TrainedModelHealth', () => {
expect(health.prop('children')).toEqual('Not started');
expect(health.prop('color')).toEqual('danger');
});
+ it('renders model not downloaded for downloadable models', () => {
+ const wrapper = shallow(
+
+ );
+ const health = wrapper.find(EuiHealth);
+ expect(health.prop('children')).toEqual('Not deployed');
+ expect(health.prop('color')).toEqual('subdued');
+ });
it('renders model stopping', () => {
const pipeline: InferencePipeline = {
...commonModelData,
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx
index 133582520deb8..329a89f0e462f 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx
@@ -15,28 +15,40 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { MlModelDeploymentState } from '../../../../../../common/types/ml';
import { TrainedModelState } from '../../../../../../common/types/pipelines';
+const modelNotDownloadedText = i18n.translate(
+ 'xpack.enterpriseSearch.inferencePipelineCard.modelState.notDownloaded',
+ {
+ defaultMessage: 'Not deployed',
+ }
+);
+const modelNotDownloadedTooltip = i18n.translate(
+ 'xpack.enterpriseSearch.inferencePipelineCard.modelState.notDownloaded.tooltip',
+ {
+ defaultMessage: 'This trained model can be deployed',
+ }
+);
const modelDownloadingText = i18n.translate(
'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloading',
{
- defaultMessage: 'Downloading',
+ defaultMessage: 'Deploying',
}
);
const modelDownloadingTooltip = i18n.translate(
'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloading.tooltip',
{
- defaultMessage: 'This trained model is downloading',
+ defaultMessage: 'This trained model is deploying',
}
);
const modelDownloadedText = i18n.translate(
'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloaded',
{
- defaultMessage: 'Downloaded',
+ defaultMessage: 'Deployed',
}
);
const modelDownloadedTooltip = i18n.translate(
'xpack.enterpriseSearch.inferencePipelineCard.modelState.downloaded.tooltip',
{
- defaultMessage: 'This trained model is downloaded and can be started',
+ defaultMessage: 'This trained model is deployed and can be started',
}
);
const modelStartedText = i18n.translate(
@@ -100,11 +112,13 @@ const modelNotDeployedTooltip = i18n.translate(
export interface TrainedModelHealthProps {
modelState: TrainedModelState | MlModelDeploymentState;
modelStateReason?: string;
+ isDownloadable?: boolean;
}
export const TrainedModelHealth: React.FC = ({
modelState,
modelStateReason,
+ isDownloadable,
}) => {
let modelHealth: {
healthColor: string;
@@ -115,9 +129,9 @@ export const TrainedModelHealth: React.FC = ({
case TrainedModelState.NotDeployed:
case MlModelDeploymentState.NotDeployed:
modelHealth = {
- healthColor: 'danger',
- healthText: modelNotDeployedText,
- tooltipText: modelNotDeployedTooltip,
+ healthColor: isDownloadable ? 'subdued' : 'danger',
+ healthText: isDownloadable ? modelNotDownloadedText : modelNotDeployedText,
+ tooltipText: isDownloadable ? modelNotDownloadedTooltip : modelNotDeployedTooltip,
};
break;
case MlModelDeploymentState.Downloading:
diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts
index 790b34a964d5b..bd02af095fe04 100644
--- a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts
+++ b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.test.ts
@@ -371,7 +371,7 @@ describe('fetchMlModels', () => {
expect(models.length).toBe(2);
expect(models[0]).toMatchObject({
modelId: ELSER_MODEL_ID,
- deploymentState: MlModelDeploymentState.Downloaded,
+ deploymentState: MlModelDeploymentState.NotDeployed,
});
expect(mockTrainedModelsProvider.getTrainedModels).toHaveBeenCalledTimes(2);
});
diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts
index 8807eabe14da7..c1af4ab69c0bc 100644
--- a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts
+++ b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts
@@ -154,8 +154,10 @@ const enrichModelWithDownloadStatus = async (
});
if (modelConfigWithDefinitionStatus && modelConfigWithDefinitionStatus.count > 0) {
+ // We're using NotDeployed for downloaded models. Downloaded is also a valid status, but we want to have the same
+ // status badge as for 3rd party models.
model.deploymentState = modelConfigWithDefinitionStatus.trained_model_configs[0].fully_defined
- ? MlModelDeploymentState.Downloaded
+ ? MlModelDeploymentState.NotDeployed
: MlModelDeploymentState.Downloading;
}
};
From ea580e69f13275105c8714b26230e4b7acceeb3d Mon Sep 17 00:00:00 2001
From: Gabriel Landau <42078554+gabriellandau@users.noreply.github.com>
Date: Tue, 19 Dec 2023 17:58:58 -0500
Subject: [PATCH 34/95] [Security Solution] Defend advanced policy option to
disable process and thread handle events (#173674)
## Summary
Defend Advanced Policy option to allow users to disable collection and
reporting of process/thread handle events. This can be used to
troubleshoot performance issues.
The feature has actually been in Defend since 8.1.0, but it was never
exposed via Kibana. Should we backport it past 8.12.0?
### 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)
### 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>
---
.../pages/policy/models/advanced_policy_schema.ts | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
index 449090d781330..52478e1f38e0c 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/models/advanced_policy_schema.ts
@@ -681,6 +681,16 @@ export const AdvancedPolicySchema: AdvancedPolicySchemaType[] = [
}
),
},
+ {
+ key: 'windows.advanced.kernel.process_handle',
+ first_supported_version: '8.1',
+ documentation: i18n.translate(
+ 'xpack.securitySolution.endpoint.policy.advanced.windows.advanced.kernel.process_handle',
+ {
+ defaultMessage: 'Capture process and thread handle events. Default: true.',
+ }
+ ),
+ },
{
key: 'windows.advanced.diagnostic.enabled',
first_supported_version: '7.11',
From 2486ed5bd1fb7cd981791272911297010e4fc6a0 Mon Sep 17 00:00:00 2001
From: Hannah Mudge
Date: Tue, 19 Dec 2023 16:24:05 -0700
Subject: [PATCH 35/95] [Controls] Re-add filtering settings (#172857)
Closes https://github.com/elastic/kibana/issues/162985
## Summary
This PR re-adds UI for the filtering settings that allow authors to
determine whether or not they want the unified search bar / time picker
to sync with the control group.
To provide some context, we **used** to have these settings, but they
were deemed over complicated and the UI to control them was removed back
in `v8.3`. Here's a screenshot of what they used to look like:
> [!NOTE]
> These settings still existed in the code, even after `v8.3` - all we
did was remove the UI to control them.
After customer feedback, we decided to re-add the UI to control these
settings, with **some** simplification - specifically, after
investigating how other apps (Maps, Lens, etc.) handle unified search
bar settings, I noticed that the control group was the **only** place
that considered the query bar to be different than / seperate from
filter pills. Therefore, rather than having **three** toggles like we
did previously (filter pills, query bar, and time picker), I combined
the filter pills + query bar settings into a single "Apply global
filters" toggle. So now, our unified search bar settings have only
**two** toggles, like so:
This is not only simpler than it was in versions less than `v8.3.0`, it
is also more consistent with how other apps do it.
> [!IMPORTANT]
> After some design feedback, I moved the old descriptions for the
"Validate user selections" and "Chain controls" settings into tooltips +
switched to a compressed `EuiSwitch` for all the settings.
>
> All of the screenshots in this PR description have been updated to
reflect this change, but some screenshots in the comments below may be
out of date.
### Summary of Control Group Settings by Version
| Version | Screenshot |
|--------|--------|
| Version <= `v8.2.0` |
|
| `v8.3.0` <= version <= `v8.12.0` |
|
| This branch (`v8.13.0`) |
|
### Checklist
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
([Link](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4638))
![image](https://github.com/elastic/kibana/assets/8698078/8a0ffab3-4783-4e64-9585-ee20ee765d6f)
- [x] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [x] Any UI touched in this PR does not create any new axe failures
(run axe in browser:
[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),
[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))
- [x] This renders correctly on smaller devices using a responsive
layout. (You can test this [in your
browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))
- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)
### For maintainers
- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
---
.../control_setting_tooltip_label.tsx | 32 ++++
.../control_group/control_group_strings.ts | 86 +++++------
.../editor/control_group_editor.tsx | 145 ++++++++++--------
.../options_list_editor_options.tsx | 35 +----
.../controls/common/control_group_settings.ts | 100 +++++++++++-
.../page_objects/dashboard_page_controls.ts | 45 ++----
.../translations/translations/fr-FR.json | 6 -
.../translations/translations/ja-JP.json | 6 -
.../translations/translations/zh-CN.json | 6 -
9 files changed, 266 insertions(+), 195 deletions(-)
create mode 100644 src/plugins/controls/public/components/control_setting_tooltip_label.tsx
diff --git a/src/plugins/controls/public/components/control_setting_tooltip_label.tsx b/src/plugins/controls/public/components/control_setting_tooltip_label.tsx
new file mode 100644
index 0000000000000..91b40e6a95e67
--- /dev/null
+++ b/src/plugins/controls/public/components/control_setting_tooltip_label.tsx
@@ -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 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, EuiIconTip } from '@elastic/eui';
+import { css } from '@emotion/react';
+
+export const ControlSettingTooltipLabel = ({
+ label,
+ tooltip,
+}: {
+ label: string;
+ tooltip: string;
+}) => (
+
+ {label}
+
+
+
+
+);
diff --git a/src/plugins/controls/public/control_group/control_group_strings.ts b/src/plugins/controls/public/control_group/control_group_strings.ts
index 651b0d6e4e317..996d86f7d676d 100644
--- a/src/plugins/controls/public/control_group/control_group_strings.ts
+++ b/src/plugins/controls/public/control_group/control_group_strings.ts
@@ -246,54 +246,46 @@ export const ControlGroupStrings = {
defaultMessage: 'Cancel',
}),
},
- validateSelections: {
- getValidateSelectionsTitle: () =>
- i18n.translate('controls.controlGroup.management.validate.title', {
- defaultMessage: 'Validate user selections',
- }),
- getValidateSelectionsSubTitle: () =>
- i18n.translate('controls.controlGroup.management.validate.subtitle', {
- defaultMessage:
- 'Automatically ignore any control selection that would result in no data.',
- }),
- },
- controlChaining: {
- getHierarchyTitle: () =>
- i18n.translate('controls.controlGroup.management.hierarchy.title', {
- defaultMessage: 'Chain controls',
- }),
- getHierarchySubTitle: () =>
- i18n.translate('controls.controlGroup.management.hierarchy.subtitle', {
- defaultMessage:
- 'Selections in one control narrow down available options in the next. Controls are chained from left to right.',
- }),
+ selectionSettings: {
+ getSelectionSettingsTitle: () =>
+ i18n.translate('controls.controlGroup.management.selectionSettings', {
+ defaultMessage: 'Selections',
+ }),
+ validateSelections: {
+ getValidateSelectionsTitle: () =>
+ i18n.translate('controls.controlGroup.management.validate.title', {
+ defaultMessage: 'Validate user selections',
+ }),
+ getValidateSelectionsSubTitle: () =>
+ i18n.translate('controls.controlGroup.management.validate.subtitle', {
+ defaultMessage:
+ 'Automatically ignore any control selection that would result in no data.',
+ }),
+ },
+ controlChaining: {
+ getHierarchyTitle: () =>
+ i18n.translate('controls.controlGroup.management.hierarchy.title', {
+ defaultMessage: 'Chain controls',
+ }),
+ getHierarchySubTitle: () =>
+ i18n.translate('controls.controlGroup.management.hierarchy.subtitle', {
+ defaultMessage:
+ 'Selections in one control narrow down available options in the next. Controls are chained from left to right.',
+ }),
+ },
},
- /** TODO: These translations aren't used but they will be once https://github.com/elastic/kibana/issues/162985 is resolved */
- querySync: {
- getQuerySettingsTitle: () =>
- i18n.translate('controls.controlGroup.management.query.searchSettingsTitle', {
- defaultMessage: 'Sync with query bar',
- }),
- getQuerySettingsSubtitle: () =>
- i18n.translate('controls.controlGroup.management.query.useAllSearchSettingsTitle', {
- defaultMessage:
- 'Keeps the control group in sync with the query bar by applying time range, filter pills, and queries from the query bar',
- }),
- getAdvancedSettingsTitle: () =>
- i18n.translate('controls.controlGroup.management.query.advancedSettings', {
- defaultMessage: 'Advanced',
- }),
- getIgnoreTimerangeTitle: () =>
- i18n.translate('controls.controlGroup.management.query.ignoreTimerange', {
- defaultMessage: 'Ignore timerange',
- }),
- getIgnoreQueryTitle: () =>
- i18n.translate('controls.controlGroup.management.query.ignoreQuery', {
- defaultMessage: 'Ignore query bar',
- }),
- getIgnoreFilterPillsTitle: () =>
- i18n.translate('controls.controlGroup.management.query.ignoreFilterPills', {
- defaultMessage: 'Ignore filter pills',
+ filteringSettings: {
+ getFilteringSettingsTitle: () =>
+ i18n.translate('controls.controlGroup.management.filteringSettings', {
+ defaultMessage: 'Filtering',
+ }),
+ getUseGlobalFiltersTitle: () =>
+ i18n.translate('controls.controlGroup.management.filtering.useGlobalFilters', {
+ defaultMessage: 'Apply global filters to controls',
+ }),
+ getUseGlobalTimeRangeTitle: () =>
+ i18n.translate('controls.controlGroup.management.filtering.useGlobalTimeRange', {
+ defaultMessage: 'Apply global time range to controls',
}),
},
},
diff --git a/src/plugins/controls/public/control_group/editor/control_group_editor.tsx b/src/plugins/controls/public/control_group/editor/control_group_editor.tsx
index 957b97ea15e46..70abc8ee86e74 100644
--- a/src/plugins/controls/public/control_group/editor/control_group_editor.tsx
+++ b/src/plugins/controls/public/control_group/editor/control_group_editor.tsx
@@ -16,30 +16,31 @@
import fastIsEqual from 'fast-deep-equal';
import React, { useCallback, useState } from 'react';
+
import {
- EuiFlyoutHeader,
+ EuiButton,
+ EuiButtonEmpty,
EuiButtonGroup,
- EuiFlyoutBody,
EuiFlexGroup,
EuiFlexItem,
- EuiTitle,
+ EuiFlyoutBody,
EuiFlyoutFooter,
- EuiButton,
+ EuiFlyoutHeader,
+ EuiForm,
EuiFormRow,
- EuiButtonEmpty,
+ EuiHorizontalRule,
EuiSpacer,
- EuiForm,
EuiSwitch,
- EuiText,
- EuiHorizontalRule,
+ EuiTitle,
} from '@elastic/eui';
-import { CONTROL_LAYOUT_OPTIONS } from './editor_constants';
-import { ControlGroupStrings } from '../control_group_strings';
-import { ControlStyle } from '../../types';
-import { ParentIgnoreSettings } from '../..';
import { ControlGroupInput } from '..';
+import { ParentIgnoreSettings } from '../..';
import { getDefaultControlGroupInput } from '../../../common';
+import { ControlSettingTooltipLabel } from '../../components/control_setting_tooltip_label';
+import { ControlStyle } from '../../types';
+import { ControlGroupStrings } from '../control_group_strings';
+import { CONTROL_LAYOUT_OPTIONS } from './editor_constants';
interface EditControlGroupProps {
initialInput: ControlGroupInput;
@@ -102,7 +103,7 @@ export const ControlGroupEditor = ({
-
+
{
// The UI copy calls this setting labelPosition, but to avoid an unnecessary migration it will be left as controlStyle in the state.
- updateControlGroupEditorSetting({ controlStyle: newControlStyle as ControlStyle });
+ updateControlGroupEditorSetting({
+ controlStyle: newControlStyle as ControlStyle,
+ });
}}
/>
-
-
-
-
+
+
+
+ updateIgnoreSetting({
+ ignoreFilters: !e.target.checked,
+ ignoreQuery: !e.target.checked,
+ })
+ }
+ checked={
+ !Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreFilters) ||
+ !Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreQuery)
+ }
+ />
+
+ updateIgnoreSetting({ ignoreTimerange: !e.target.checked })}
+ checked={!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreTimerange)}
+ />
+
+
+
+
+
+
+ }
checked={!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreValidations)}
onChange={(e) => updateIgnoreSetting({ ignoreValidations: !e.target.checked })}
/>
-
-
-
-
- {ControlGroupStrings.management.validateSelections.getValidateSelectionsTitle()}
-
-
-
-
- {ControlGroupStrings.management.validateSelections.getValidateSelectionsSubTitle()}
-
-
-
-
-
-
-
-
+
+ }
checked={controlGroupEditorState.chainingSystem === 'HIERARCHICAL'}
onChange={(e) =>
updateControlGroupEditorSetting({
@@ -156,31 +183,25 @@ export const ControlGroupEditor = ({
})
}
/>
-
-
-
- {ControlGroupStrings.management.controlChaining.getHierarchyTitle()}
-
-
- {ControlGroupStrings.management.controlChaining.getHierarchySubTitle()}
-
-
-
+
+
+
{controlCount > 0 && (
<>
-
-
- {ControlGroupStrings.management.getDeleteAllButtonTitle()}
-
+
+
+ {ControlGroupStrings.management.getDeleteAllButtonTitle()}
+
+
>
)}
diff --git a/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx b/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx
index 74e8d61ed218c..0c72daac89913 100644
--- a/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx
+++ b/src/plugins/controls/public/options_list/components/options_list_editor_options.tsx
@@ -9,17 +9,7 @@
import React, { useEffect, useMemo, useState } from 'react';
import useAsync from 'react-use/lib/useAsync';
-import {
- Direction,
- EuiFlexGroup,
- EuiFlexItem,
- EuiFormRow,
- EuiIconTip,
- EuiLoadingSpinner,
- EuiRadioGroup,
- EuiSwitch,
-} from '@elastic/eui';
-import { css } from '@emotion/react';
+import { Direction, EuiFormRow, EuiLoadingSpinner, EuiRadioGroup, EuiSwitch } from '@elastic/eui';
import { ControlEditorProps, OptionsListEmbeddableInput } from '../..';
import {
@@ -33,20 +23,7 @@ import {
} from '../../../common/options_list/suggestions_sorting';
import { pluginServices } from '../../services';
import { OptionsListStrings } from './options_list_strings';
-
-const TooltipText = ({ label, tooltip }: { label: string; tooltip: string }) => (
-
- {label}
-
-
-
-
-);
+import { ControlSettingTooltipLabel } from '../../components/control_setting_tooltip_label';
const selectionOptions = [
{
@@ -65,7 +42,7 @@ const allSearchOptions = [
{
id: 'prefix',
label: (
-
@@ -75,7 +52,7 @@ const allSearchOptions = [
{
id: 'wildcard',
label: (
-
@@ -85,7 +62,7 @@ const allSearchOptions = [
{
id: 'exact',
label: (
-
@@ -207,7 +184,7 @@ export const OptionsListEditorOptions = ({
diff --git a/test/functional/apps/dashboard_elements/controls/common/control_group_settings.ts b/test/functional/apps/dashboard_elements/controls/common/control_group_settings.ts
index aa3ae89015c5e..f4359f9887c59 100644
--- a/test/functional/apps/dashboard_elements/controls/common/control_group_settings.ts
+++ b/test/functional/apps/dashboard_elements/controls/common/control_group_settings.ts
@@ -6,21 +6,28 @@
* Side Public License, v 1.
*/
-import { OPTIONS_LIST_CONTROL } from '@kbn/controls-plugin/common';
+import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '@kbn/controls-plugin/common';
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
- const testSubjects = getService('testSubjects');
const find = getService('find');
- const { dashboardControls, dashboard } = getPageObjects(['dashboardControls', 'dashboard']);
+ const queryBar = getService('queryBar');
+ const filterBar = getService('filterBar');
+ const testSubjects = getService('testSubjects');
+ const { dashboardControls, dashboard, timePicker } = getPageObjects([
+ 'dashboardControls',
+ 'dashboard',
+ 'timePicker',
+ ]);
describe('Dashboard control group settings', () => {
before(async () => {
await dashboard.navigateToApp();
await dashboard.gotoDashboardLandingPage();
await dashboard.clickNewDashboard();
+ await timePicker.setDefaultDataRange();
await dashboard.saveDashboard('Test Control Group Settings');
});
@@ -76,6 +83,93 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
});
+ describe('filtering settings', async () => {
+ let firstOptionsListId: string;
+ let beforeCount: number;
+
+ let rangeSliderId: string;
+ let beforeRange: number;
+
+ const getRange = async () => {
+ await dashboardControls.rangeSliderWaitForLoading(rangeSliderId);
+ const lower = await dashboardControls.rangeSliderGetLowerBoundAttribute(
+ rangeSliderId,
+ 'placeholder'
+ );
+ const upper = await dashboardControls.rangeSliderGetUpperBoundAttribute(
+ rangeSliderId,
+ 'placeholder'
+ );
+ return parseInt(upper, 10) - parseInt(lower, 10);
+ };
+
+ before(async () => {
+ await dashboardControls.createControl({
+ controlType: RANGE_SLIDER_CONTROL,
+ dataViewTitle: 'animals-*',
+ fieldName: 'weightLbs',
+ });
+ await dashboard.clickQuickSave();
+
+ firstOptionsListId = (await dashboardControls.getAllControlIds())[0];
+ await dashboardControls.optionsListWaitForLoading(firstOptionsListId);
+ await dashboardControls.optionsListOpenPopover(firstOptionsListId);
+ beforeCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
+
+ rangeSliderId = (await dashboardControls.getAllControlIds())[2];
+ beforeRange = await getRange();
+ });
+
+ describe('do not apply global filters', async () => {
+ it('- filter pills', async () => {
+ await filterBar.addFilter({ field: 'animal.keyword', operation: 'is', value: 'cat' });
+ await dashboardControls.optionsListOpenPopover(firstOptionsListId);
+ let afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
+ expect(afterCount).to.be.lessThan(beforeCount);
+ await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
+
+ await dashboardControls.updateFilterSyncSetting(false);
+ await dashboardControls.optionsListOpenPopover(firstOptionsListId);
+ afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
+ expect(afterCount).to.be.equal(beforeCount);
+
+ await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
+ await filterBar.removeAllFilters();
+ });
+
+ it('- query', async () => {
+ await queryBar.setQuery('weightLbs < 40');
+ await queryBar.submitQuery();
+ let afterRange = await getRange();
+ expect(afterRange).to.be.equal(beforeRange);
+ await dashboardControls.rangeSliderEnsurePopoverIsClosed(rangeSliderId);
+
+ await dashboardControls.updateFilterSyncSetting(true);
+ afterRange = await getRange();
+ expect(afterRange).to.be.lessThan(beforeRange);
+ await dashboardControls.rangeSliderEnsurePopoverIsClosed(rangeSliderId);
+ await queryBar.clearQuery();
+ await queryBar.submitQuery();
+ });
+ });
+
+ it('do not apply time range', async () => {
+ await timePicker.setCommonlyUsedTime('Today');
+ await dashboardControls.optionsListOpenPopover(firstOptionsListId);
+ let afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
+ expect(afterCount).to.be.equal(0);
+ await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
+
+ await dashboardControls.updateTimeRangeSyncSetting(false);
+ await dashboardControls.optionsListOpenPopover(firstOptionsListId);
+ afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
+ expect(afterCount).to.be.equal(beforeCount);
+ await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
+ await timePicker.setDefaultDataRange();
+ await dashboardControls.updateTimeRangeSyncSetting(true);
+ });
+ });
+
describe('flyout only show settings that are relevant', async () => {
before(async () => {
await dashboard.switchToEditMode();
diff --git a/test/functional/page_objects/dashboard_page_controls.ts b/test/functional/page_objects/dashboard_page_controls.ts
index 4e1e9c1ccfdc1..af6f3f81563d3 100644
--- a/test/functional/page_objects/dashboard_page_controls.ts
+++ b/test/functional/page_objects/dashboard_page_controls.ts
@@ -185,48 +185,20 @@ export class DashboardPageControls extends FtrService {
await this.testSubjects.click('control-group-editor-save');
}
- public async updateAllQuerySyncSettings(querySync: boolean) {
- this.log.debug(`Update all control group query sync settings to ${querySync}`);
+ public async updateFilterSyncSetting(querySync: boolean) {
+ this.log.debug(`Update filter sync setting to ${querySync}`);
await this.openControlGroupSettingsFlyout();
- await this.setSwitchState(querySync, 'control-group-query-sync');
+ await this.setSwitchState(querySync, 'control-group-filter-sync');
await this.testSubjects.click('control-group-editor-save');
}
- public async ensureAdvancedQuerySyncIsOpened() {
- const advancedAccordion = await this.testSubjects.find(`control-group-query-sync-advanced`);
- const opened = await advancedAccordion.elementHasClass('euiAccordion-isOpen');
- if (!opened) {
- await this.testSubjects.click(`control-group-query-sync-advanced`);
- await this.retry.try(async () => {
- expect(await advancedAccordion.elementHasClass('euiAccordion-isOpen')).to.be(true);
- });
- }
- }
-
- public async updateSyncTimeRangeAdvancedSetting(syncTimeRange: boolean) {
- this.log.debug(`Update filter sync advanced setting to ${syncTimeRange}`);
+ public async updateTimeRangeSyncSetting(syncTimeRange: boolean) {
+ this.log.debug(`Update time range sync setting to ${syncTimeRange}`);
await this.openControlGroupSettingsFlyout();
- await this.ensureAdvancedQuerySyncIsOpened();
await this.setSwitchState(syncTimeRange, 'control-group-query-sync-time-range');
await this.testSubjects.click('control-group-editor-save');
}
- public async updateSyncQueryAdvancedSetting(syncQuery: boolean) {
- this.log.debug(`Update filter sync advanced setting to ${syncQuery}`);
- await this.openControlGroupSettingsFlyout();
- await this.ensureAdvancedQuerySyncIsOpened();
- await this.setSwitchState(syncQuery, 'control-group-query-sync-query');
- await this.testSubjects.click('control-group-editor-save');
- }
-
- public async updateSyncFilterAdvancedSetting(syncFilters: boolean) {
- this.log.debug(`Update filter sync advanced setting to ${syncFilters}`);
- await this.openControlGroupSettingsFlyout();
- await this.ensureAdvancedQuerySyncIsOpened();
- await this.setSwitchState(syncFilters, 'control-group-query-sync-filters');
- await this.testSubjects.click('control-group-editor-save');
- }
-
/* -----------------------------------------------------------
Individual controls functions
----------------------------------------------------------- */
@@ -392,10 +364,11 @@ export class DashboardPageControls extends FtrService {
public async optionsListOpenPopover(controlId: string) {
this.log.debug(`Opening popover for Options List: ${controlId}`);
-
- await this.testSubjects.click(`optionsList-control-${controlId}`);
await this.retry.try(async () => {
- await this.testSubjects.existOrFail(`optionsList-control-popover`);
+ await this.testSubjects.click(`optionsList-control-${controlId}`);
+ await this.retry.waitForWithTimeout('popover to open', 500, async () => {
+ return await this.testSubjects.exists(`optionsList-control-popover`);
+ });
});
}
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 779921068028e..ed4999bec7334 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -488,12 +488,6 @@
"controls.controlGroup.management.layout.large": "Large",
"controls.controlGroup.management.layout.medium": "Moyenne",
"controls.controlGroup.management.layout.small": "Petite",
- "controls.controlGroup.management.query.advancedSettings": "Avancé",
- "controls.controlGroup.management.query.ignoreFilterPills": "Ignorer les pilules de filtre",
- "controls.controlGroup.management.query.ignoreQuery": "Ignorer la barre de requête",
- "controls.controlGroup.management.query.ignoreTimerange": "Ignorer la plage temporelle",
- "controls.controlGroup.management.query.searchSettingsTitle": "Synchronisation avec la barre de requête",
- "controls.controlGroup.management.query.useAllSearchSettingsTitle": "Assure la synchronisation entre le groupe de contrôle et la barre de requête, en appliquant une plage temporelle, des pilules de filtre et des requêtes de la barre de requête",
"controls.controlGroup.management.validate.subtitle": "Ignorez automatiquement toutes les sélections de contrôle qui ne donneraient aucune donnée.",
"controls.controlGroup.management.validate.title": "Valider les sélections utilisateur",
"controls.controlGroup.timeSlider.title": "Curseur temporel",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 27125a6261b28..c8fb3f513fa9b 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -488,12 +488,6 @@
"controls.controlGroup.management.layout.large": "大",
"controls.controlGroup.management.layout.medium": "中",
"controls.controlGroup.management.layout.small": "小",
- "controls.controlGroup.management.query.advancedSettings": "高度な設定",
- "controls.controlGroup.management.query.ignoreFilterPills": "フィルターピルを無視",
- "controls.controlGroup.management.query.ignoreQuery": "クエリバーを無視",
- "controls.controlGroup.management.query.ignoreTimerange": "時間範囲を無視",
- "controls.controlGroup.management.query.searchSettingsTitle": "クエリバーと同期",
- "controls.controlGroup.management.query.useAllSearchSettingsTitle": "時間範囲、フィルターピル、クエリバーからのクエリを適用して、コントロールグループを常にクエリと同期します",
"controls.controlGroup.management.validate.subtitle": "データがないコントロール選択は自動的に無視されます。",
"controls.controlGroup.management.validate.title": "ユーザー選択を検証",
"controls.controlGroup.timeSlider.title": "時間スライダー",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 9f4ab71dc071c..2d4e05c06f1a4 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -488,12 +488,6 @@
"controls.controlGroup.management.layout.large": "大",
"controls.controlGroup.management.layout.medium": "中",
"controls.controlGroup.management.layout.small": "小",
- "controls.controlGroup.management.query.advancedSettings": "高级",
- "controls.controlGroup.management.query.ignoreFilterPills": "忽略筛选胶囊",
- "controls.controlGroup.management.query.ignoreQuery": "忽略查询栏",
- "controls.controlGroup.management.query.ignoreTimerange": "忽略时间范围",
- "controls.controlGroup.management.query.searchSettingsTitle": "与查询栏同步",
- "controls.controlGroup.management.query.useAllSearchSettingsTitle": "通过从查询栏应用时间范围、筛选胶囊和查询,使控件组与查询栏保持同步",
"controls.controlGroup.management.validate.subtitle": "自动忽略所有不会生成数据的控件选择。",
"controls.controlGroup.management.validate.title": "验证用户选择",
"controls.controlGroup.timeSlider.title": "时间滑块",
From 3df2c4f9662c737a32bae92c3fe81b5f0c1600c8 Mon Sep 17 00:00:00 2001
From: Lisa Cawley
Date: Tue, 19 Dec 2023 20:31:11 -0800
Subject: [PATCH 36/95] [DOCS] Automate Tines connector screenshots (#166313)
---
.../connectors/action-types/tines.asciidoc | 14 +----
.../connectors/images/tines-alerting.png | Bin 78054 -> 0 bytes
.../connectors/images/tines-connector.png | Bin 61197 -> 158992 bytes
.../connectors/images/tines-params-test.png | Bin 46631 -> 128864 bytes
.../stack_connectors/index.ts | 1 +
.../stack_connectors/tines_connector.ts | 52 ++++++++++++++++++
6 files changed, 56 insertions(+), 11 deletions(-)
delete mode 100644 docs/management/connectors/images/tines-alerting.png
create mode 100644 x-pack/test/screenshot_creation/apps/response_ops_docs/stack_connectors/tines_connector.ts
diff --git a/docs/management/connectors/action-types/tines.asciidoc b/docs/management/connectors/action-types/tines.asciidoc
index cdaf56912d0f0..c9888ab7b9087 100644
--- a/docs/management/connectors/action-types/tines.asciidoc
+++ b/docs/management/connectors/action-types/tines.asciidoc
@@ -19,6 +19,7 @@ or as needed when you're creating a rule. For example:
[role="screenshot"]
image::management/connectors/images/tines-connector.png[Tines connector]
+// NOTE: This is an autogenerated screenshot. Do not edit it directly.
[float]
[[tines-connector-configuration]]
@@ -34,23 +35,14 @@ API Token:: A Tines API token created by the user. For more information, refer
[[tines-action-parameters]]
=== Test connectors
-Tines actions have the following parameters.
-
-Story:: The Story to send the events to.
-Webhook:: The Webhook action from the previous story that will receive the events, it is the data entry point.
-
You can test connectors with the <> or
as you're creating or editing the connector in {kib}. For example:
[role="screenshot"]
image::management/connectors/images/tines-params-test.png[Tines params test]
+// NOTE: This is an autogenerated screenshot. Do not edit it directly.
-Once the Tines connector has been configured in an alerting rule:
-
-[role="screenshot"]
-image::management/connectors/images/tines-alerting.png[Tines rule alert]
-
-It will send a POST request to the Tines webhook action on every action that runs with at least one result.
+If you create a rule action that uses the Tines connector, you can likewise configure the POST request that is sent to the Tines webhook action when the rule conditions are met.
[float]
[[webhookUrlFallback-tines-configuration]]
diff --git a/docs/management/connectors/images/tines-alerting.png b/docs/management/connectors/images/tines-alerting.png
deleted file mode 100644
index 765cd95abb10341d8a49c728348123f9f6f3a7ac..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 78054
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