From b713dc94eb6a2c44267fd5dcda13b5526e918f0a Mon Sep 17 00:00:00 2001 From: Saikat Sarkar <132922331+saikatsarkar056@users.noreply.github.com> Date: Tue, 24 Jun 2025 10:54:04 -0600 Subject: [PATCH] [Home page V1] Create a home page in serverless env (#223172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR introduces a new Search Home page. Currently, the homepage experience differs across Classic nav, Solution nav, and Serverless. Our goal is to unify these into a consistent, foundational experience that we can iterate on to create a more personalized and customizable homepage for Elasticsearch users. The new page includes: - An option to connect to Elasticsearch - File upload and sample dataset ingestion - Entry points to explore Elastic’s AI Search capabilities - Quick access to Observability and Security solutions - Links to Search Labs, Python notebooks, and Elasticsearch documentation https://github.com/user-attachments/assets/7b1b5330-59b4-43b7-aa5b-000fcd2654e2 ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [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/src/platform/packages/shared/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] 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 was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging. - [ ] [See some risk examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) - [ ] ... --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Lisa Cawley Co-authored-by: Rodney Norris --- config/serverless.es.yml | 3 + .../shared/kbn-doc-links/src/get_doc_links.ts | 6 + .../shared/kbn-doc-links/src/types.ts | 6 + .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../search_homepage/common/doc_links.ts | 31 ++ .../plugins/search_homepage/common/routes.ts | 10 + .../plugins/search_homepage/common/types.ts | 25 ++ .../search_homepage/public/application.tsx | 20 +- .../public/assets/keyword_search.svg | 20 ++ .../public/assets/search_homepage_dark.svg | 274 ++++++++++++++++++ .../public/assets/search_homepage_light.svg | 269 +++++++++++++++++ .../public/assets/semantic_search.svg | 54 ++++ .../public/assets/vector_search.svg | 15 + .../ai_search_capabilities.tsx | 94 ++++++ .../ai_search_workflow.tsx | 80 +++++ .../ai_search_capabilities/keyword_search.tsx | 53 ++++ .../semantic_search.tsx | 53 ++++ .../ai_search_capabilities/vector_search.tsx | 53 ++++ .../workflow_feature_bullet.tsx | 22 ++ .../alternate_solutions.tsx | 43 +++ .../alternate_solutions/observability.tsx | 124 ++++++++ .../alternate_solutions/security.tsx | 110 +++++++ .../components/connect_to_elasticsearch.tsx | 175 +++++++++++ .../connect_to_elasticsearch_side_panel.tsx | 110 +++++++ .../public/components/console_link_button.tsx | 48 --- .../dive_deeper_with_elasticsearch.tsx | 88 ++++++ .../components/dive_deeper/doc_callouts.tsx | 50 ++++ .../components/endpoints_header_action.tsx | 52 ---- .../components/feature_update_group.tsx | 30 ++ .../public/components/footer/footer.tsx | 33 +++ .../public/components/search_homepage.tsx | 9 +- .../components/search_homepage_body.tsx | 31 +- .../components/search_homepage_header.tsx | 85 ++++-- .../public/components/stack_app.tsx | 2 +- .../search_homepage/public/constants.ts | 18 ++ .../public/hooks/api/use_api_key.tsx | 20 ++ .../hooks/api/use_indices_status_query.ts | 32 ++ .../public/hooks/api/use_user_permissions.ts | 25 ++ .../use_asset_base_path.ts} | 11 +- .../public/hooks/use_elasticsearch_url.ts | 27 ++ .../hooks/use_search_home_page_redirect.tsx | 48 +++ .../plugins/search_homepage/public/index.ts | 6 +- .../plugins/search_homepage/public/plugin.ts | 37 +-- .../public/services/query_client.ts | 30 ++ .../plugins/search_homepage/public/types.ts | 28 +- .../public/utils/get_error_message.ts | 43 +++ .../search_homepage/public/utils/indices.ts | 23 ++ .../plugins/search_homepage/server/config.ts | 6 - .../search_homepage/server/lib/status.ts | 72 +++++ .../plugins/search_homepage/server/plugin.ts | 24 +- .../server/routes/api_key_routes.ts | 51 ++++ .../search_homepage/server/routes/index.ts | 17 ++ .../search_homepage/server/routes/status.ts | 73 +++++ .../server/utils/error_handler.ts | 28 ++ .../server/utils/index_utils.ts | 19 ++ .../plugins/search_homepage/tsconfig.json | 9 +- .../plugins/serverless_search/kibana.jsonc | 1 + .../public/application/constants.ts | 1 + .../public/navigation_tree.ts | 8 + .../serverless_search/public/plugin.ts | 34 +-- .../plugins/serverless_search/public/types.ts | 6 + .../plugins/serverless_search/tsconfig.json | 3 +- .../page_objects/svl_search_homepage.ts | 44 ++- .../functional/test_suites/search/config.ts | 3 + .../functional/test_suites/search/index.ts | 1 + .../test_suites/search/navigation.ts | 1 + .../test_suites/search/search_homepage.ts | 227 +++++++++++---- 69 files changed, 2775 insertions(+), 285 deletions(-) create mode 100644 x-pack/solutions/search/plugins/search_homepage/common/doc_links.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/common/routes.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/common/types.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/assets/keyword_search.svg create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_dark.svg create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_light.svg create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/assets/semantic_search.svg create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/assets/vector_search.svg create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_capabilities.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_workflow.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/keyword_search.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/semantic_search.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/vector_search.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/workflow_feature_bullet.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/alternate_solutions.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/observability.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/security.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch_side_panel.tsx delete mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/console_link_button.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/dive_deeper_with_elasticsearch.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/doc_callouts.tsx delete mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/endpoints_header_action.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/feature_update_group.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/components/footer/footer.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/constants.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/hooks/api/use_api_key.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/hooks/api/use_indices_status_query.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/hooks/api/use_user_permissions.ts rename x-pack/solutions/search/plugins/search_homepage/public/{feature_flags.ts => hooks/use_asset_base_path.ts} (50%) create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/hooks/use_elasticsearch_url.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/hooks/use_search_home_page_redirect.tsx create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/services/query_client.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/utils/get_error_message.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/public/utils/indices.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/lib/status.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/routes/api_key_routes.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/routes/index.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/routes/status.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/utils/error_handler.ts create mode 100644 x-pack/solutions/search/plugins/search_homepage/server/utils/index_utils.ts diff --git a/config/serverless.es.yml b/config/serverless.es.yml index c9ff7a0c78bd..1b8ca16edbae 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -109,6 +109,9 @@ xpack.searchNotebooks.catalog.url: https://elastic-enterprise-search.s3.us-east- # Semantic text UI xpack.index_management.dev.enableSemanticText: true +# Search Homepage +xpack.searchHomepage.enabled: true + # AI Assistant config xpack.observabilityAIAssistant.enabled: true xpack.searchAssistant.enabled: true diff --git a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts index fc9260e9634a..0e0262cbd4ed 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts @@ -193,6 +193,12 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D upgrade9x: `${ENTERPRISE_SEARCH_DOCS}upgrading-to-9-x.html`, usersAccess: `${ENTERPRISE_SEARCH_DOCS}users-access.html`, }, + searchHomepage: { + visitSearchLabs: `${ELASTIC_WEBSITE_URL}search-labs`, + notebooksExamples: `${ELASTIC_WEBSITE_URL}search-labs/tutorials/examples`, + customerEngineerRequestForm: `${ELASTIC_WEBSITE_URL}contact/ce-help`, + elasticCommunity: `${ELASTIC_WEBSITE_URL}community/`, + }, metricbeat: { base: `${ELASTIC_DOCS}reference/beats/metricbeat`, configure: `${ELASTIC_DOCS}reference/beats/metricbeat/configuring-howto-metricbeat`, diff --git a/src/platform/packages/shared/kbn-doc-links/src/types.ts b/src/platform/packages/shared/kbn-doc-links/src/types.ts index f85e7bdad0d1..1266a27a22a4 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/types.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/types.ts @@ -80,6 +80,12 @@ export interface DocLinks { readonly auditdModule: string; readonly systemModule: string; }; + readonly searchHomepage: { + readonly visitSearchLabs: string; + readonly notebooksExamples: string; + readonly customerEngineerRequestForm: string; + readonly elasticCommunity: string; + }; readonly metricbeat: { readonly base: string; readonly configure: string; diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 58d97b48962b..558bcf84ad43 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -33704,8 +33704,6 @@ "xpack.searchAssistant.navControl.initFailureErrorTitle": "Impossible d’initialiser l'assistant d’AI", "xpack.searchAssistant.navControl.openTheAIAssistantPopoverLabel": "Ouvrir l'assistant d'IA", "xpack.searchHomepage.appTitle": "Accueil", - "xpack.searchHomepage.consoleLink.buttonText": "Démarrez rapidement dans la Console", - "xpack.searchHomepage.header.endpointsButtonLabel": "Points de terminaison et clés d'API", "xpack.searchHomepage.pageTitle": "Bienvenue dans Search", "xpack.searchIndices.breadcrumbs.indexManagement.indices.label": "Index", "xpack.searchIndices.breadcrumbs.indexManagement.label": "Gestion des index", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index e9536122cfdd..a601b07c4441 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -33743,8 +33743,6 @@ "xpack.searchAssistant.navControl.initFailureErrorTitle": "AI Assistantを初期化できませんでした", "xpack.searchAssistant.navControl.openTheAIAssistantPopoverLabel": "AI Assistantを開く", "xpack.searchHomepage.appTitle": "ホーム", - "xpack.searchHomepage.consoleLink.buttonText": "コンソールをすばやく開始", - "xpack.searchHomepage.header.endpointsButtonLabel": "エンドポイントとAPIキー", "xpack.searchHomepage.pageTitle": "Searchへようこそ", "xpack.searchIndices.breadcrumbs.indexManagement.indices.label": "インデックス", "xpack.searchIndices.breadcrumbs.indexManagement.label": "インデックス管理", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 39f5dbb203ef..f3870518006a 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -33729,8 +33729,6 @@ "xpack.searchAssistant.navControl.initFailureErrorTitle": "无法初始化 AI 助手", "xpack.searchAssistant.navControl.openTheAIAssistantPopoverLabel": "打开 AI 助手", "xpack.searchHomepage.appTitle": "主页", - "xpack.searchHomepage.consoleLink.buttonText": "在 Console 中快速开始", - "xpack.searchHomepage.header.endpointsButtonLabel": "终端和 API 密钥", "xpack.searchHomepage.pageTitle": "欢迎使用 Search", "xpack.searchIndices.breadcrumbs.indexManagement.indices.label": "索引", "xpack.searchIndices.breadcrumbs.indexManagement.label": "索引管理", diff --git a/x-pack/solutions/search/plugins/search_homepage/common/doc_links.ts b/x-pack/solutions/search/plugins/search_homepage/common/doc_links.ts new file mode 100644 index 000000000000..ee3964578943 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/common/doc_links.ts @@ -0,0 +1,31 @@ +/* + * Copyright 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 { DocLinks } from '@kbn/doc-links'; + +class ESDocLinks { + public kibanaFeedback: string = ''; + public elasticCommunity: string = ''; + public elasticsearchDocs: string = ''; + public visitSearchLabs: string = ''; + public notebooksExamples: string = ''; + public customerEngineerRequestForm: string = ''; + public analyzeLogs: string = ''; + constructor() {} + + setDocLinks(newDocLinks: DocLinks) { + this.kibanaFeedback = newDocLinks.kibana.feedback; + this.elasticCommunity = newDocLinks.searchHomepage.elasticCommunity; + this.elasticsearchDocs = newDocLinks.elasticsearch.gettingStarted; + this.visitSearchLabs = newDocLinks.searchHomepage.visitSearchLabs; + this.notebooksExamples = newDocLinks.searchHomepage.notebooksExamples; + this.analyzeLogs = newDocLinks.serverlessSearch.integrations; + this.customerEngineerRequestForm = newDocLinks.searchHomepage.customerEngineerRequestForm; + } +} + +export const docLinks = new ESDocLinks(); diff --git a/x-pack/solutions/search/plugins/search_homepage/common/routes.ts b/x-pack/solutions/search/plugins/search_homepage/common/routes.ts new file mode 100644 index 000000000000..c284bf322292 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/common/routes.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const GET_STATUS_ROUTE = '/internal/search_homepage/status'; +export const GET_USER_PRIVILEGES_ROUTE = '/internal/search_homepage/start_privileges/{indexName}'; +export const GET_API_KEYS_ROUTE = '/internal/search_homepage/api_keys'; diff --git a/x-pack/solutions/search/plugins/search_homepage/common/types.ts b/x-pack/solutions/search/plugins/search_homepage/common/types.ts new file mode 100644 index 000000000000..accb9318743d --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/common/types.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ApiKey } from '@kbn/security-plugin-types-common'; + +export interface IndicesStatusResponse { + indexNames: string[]; +} + +export interface UserStartPrivilegesResponse { + privileges: { + canCreateApiKeys: boolean; + canManageIndex: boolean; + canDeleteDocuments: boolean; + }; +} + +export interface ApiKeysResponse { + apiKeys: ApiKey[]; + canManageOwnApiKey: boolean; +} diff --git a/x-pack/solutions/search/plugins/search_homepage/public/application.tsx b/x-pack/solutions/search/plugins/search_homepage/public/application.tsx index 5d2a04a97cc6..dd6f62d879f7 100644 --- a/x-pack/solutions/search/plugins/search_homepage/public/application.tsx +++ b/x-pack/solutions/search/plugins/search_homepage/public/application.tsx @@ -12,24 +12,28 @@ import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { I18nProvider } from '@kbn/i18n-react'; import { Router } from '@kbn/shared-ux-router'; -import { SearchHomepageServicesContext } from './types'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { SearchHomepageServicesContextDeps } from './types'; import { HomepageRouter } from './router'; import { UsageTrackerContextProvider } from './contexts/usage_tracker_context'; export const renderApp = async ( core: CoreStart, - services: SearchHomepageServicesContext, - element: HTMLElement + services: SearchHomepageServicesContextDeps, + element: HTMLElement, + queryClient: QueryClient ) => { ReactDOM.render( - - - - - + + + + + + + , diff --git a/x-pack/solutions/search/plugins/search_homepage/public/assets/keyword_search.svg b/x-pack/solutions/search/plugins/search_homepage/public/assets/keyword_search.svg new file mode 100644 index 000000000000..0f4dc819627a --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/assets/keyword_search.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_dark.svg b/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_dark.svg new file mode 100644 index 000000000000..c8f5e590555e --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_dark.svg @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_light.svg b/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_light.svg new file mode 100644 index 000000000000..c22fa45c296e --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/assets/search_homepage_light.svg @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/x-pack/solutions/search/plugins/search_homepage/public/assets/semantic_search.svg b/x-pack/solutions/search/plugins/search_homepage/public/assets/semantic_search.svg new file mode 100644 index 000000000000..613236c95c65 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/assets/semantic_search.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/x-pack/solutions/search/plugins/search_homepage/public/assets/vector_search.svg b/x-pack/solutions/search/plugins/search_homepage/public/assets/vector_search.svg new file mode 100644 index 000000000000..ed30c8391250 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/assets/vector_search.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_capabilities.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_capabilities.tsx new file mode 100644 index 000000000000..c6525f07d38a --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_capabilities.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiFlexGroup, + EuiFlexItem, + EuiListGroup, + EuiListGroupItem, + EuiTitle, + useCurrentEuiBreakpoint, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; + +import { KeywordSearch } from './keyword_search'; +import { SemanticSearch } from './semantic_search'; +import { VectorSearch } from './vector_search'; + +const SEARCH_CAPABILITIES = [ + { + label: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch', { + defaultMessage: 'Semantic search', + }), + value: 'semantic', + }, + { + label: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch', { + defaultMessage: 'Vector search', + }), + value: 'vector', + }, + { + label: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch', { + defaultMessage: 'Keyword search', + }), + value: 'keyword', + }, +]; + +const capabilityComponents: Record = { + semantic: SemanticSearch, + vector: VectorSearch, + keyword: KeywordSearch, +}; + +export const AISearchCapabilities: React.FC = () => { + const [selectedCapability, setSelectedCapability] = useState( + SEARCH_CAPABILITIES[0].value + ); + const currentBreakpoint = useCurrentEuiBreakpoint(); + + const SelectedComponent = capabilityComponents[selectedCapability]; + + return ( + + + +

+ {i18n.translate('xpack.searchHomepage.aiSearchCapabilities.title', { + defaultMessage: 'Explore Elastic’s AI search capabilities', + })} +

+
+
+ + + + + {SEARCH_CAPABILITIES.map((capability) => ( + setSelectedCapability(capability.value)} + isActive={selectedCapability === capability.value} + data-test-subj={`aiSearchCapabilities-item-${capability.value}`} + /> + ))} + + + + + + + +
+ ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_workflow.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_workflow.tsx new file mode 100644 index 000000000000..317993a30053 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/ai_search_workflow.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiImage, + EuiTitle, + EuiSpacer, + EuiButton, + useCurrentEuiBreakpoint, +} from '@elastic/eui'; + +import { useKibana } from '../../hooks/use_kibana'; + +import { WorkflowFeatureBullet } from './workflow_feature_bullet'; + +interface WorkflowProps { + image: string; + imageAlt: string; + heading: string; + subheading: string; + featureBullets: string[]; + buttonLabel: string; + dataTestSubj: string; +} + +export const AISearchWorkflow = ({ capability }: { capability: WorkflowProps }) => { + const currentBreakpoint = useCurrentEuiBreakpoint(); + const { share } = useKibana().services; + const createIndexUrl = share?.url.locators.get('SEARCH_CREATE_INDEX')?.useUrl({}); + + return ( + + + + + + + + + +

{capability.heading}

+
+ + +

{capability.subheading}

+
+ + + + {capability.featureBullets.map((item: string, index: number) => ( + + + + ))} + + + + + + {capability.buttonLabel} + + +
+
+
+ ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/keyword_search.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/keyword_search.tsx new file mode 100644 index 000000000000..6b2a300a40b5 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/keyword_search.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { AISearchWorkflow } from './ai_search_workflow'; +import { useAssetBasePath } from '../../hooks/use_asset_base_path'; + +export const KeywordSearch: React.FC = () => { + const assetBasePath = useAssetBasePath(); + + const keywordSearchText = { + image: `${assetBasePath}/keyword_search.svg`, + imageAlt: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch.imageAlt', { + defaultMessage: 'Keyword search', + }), + heading: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch.title', { + defaultMessage: 'Setup your application with Elasticsearch’s full-text search capabilities', + }), + subheading: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.keywordSearch.description', + { + defaultMessage: + 'Use a semantic_text field and Elastic’s built-in ELSER machine learning model.', + } + ), + featureBullets: [ + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch.firstLine', { + defaultMessage: 'Enhanced query flexibility to create complex search functionalities.', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch.secondLine', { + defaultMessage: 'Scalable architecture accommodates growing data sets.', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.keywordSearch.thirdLine', { + defaultMessage: 'Enable precise results by targeting for users or other query conditions.', + }), + ], + buttonLabel: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.keywordSearch.createKeywordIndex', + { + defaultMessage: 'Create a keyword index', + } + ), + dataTestSubj: 'createKeywordIndexButton', + }; + + return ; +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/semantic_search.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/semantic_search.tsx new file mode 100644 index 000000000000..8b085764d06b --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/semantic_search.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { AISearchWorkflow } from './ai_search_workflow'; +import { useAssetBasePath } from '../../hooks/use_asset_base_path'; + +export const SemanticSearch: React.FC = () => { + const assetBasePath = useAssetBasePath(); + + const semanticSearchText = { + image: `${assetBasePath}/semantic_search.svg`, + imageAlt: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch.imageAlt', { + defaultMessage: 'Semantic search', + }), + heading: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch.title', { + defaultMessage: 'Enhance search accuracy with advanced semantic capabilities.', + }), + subheading: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.semanticSearch.description', + { + defaultMessage: + 'Leverage the semantic_text field and ELSER machine learning model for enhanced data analysis.', + } + ), + featureBullets: [ + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch.firstLine', { + defaultMessage: 'Use Elastic’s inference service or connect your own model provider', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch.SecondLine', { + defaultMessage: 'Default chunking strategies or customize your own', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.semanticSearch.ThirdLine', { + defaultMessage: 'Combine semantic capabilities with traditional search methods.', + }), + ], + buttonLabel: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.semanticSearch.createSemanticOptimizedIndex', + { + defaultMessage: 'Create a semantic optimized index', + } + ), + dataTestSubj: 'createSemanticOptimizedIndexButton', + }; + + return ; +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/vector_search.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/vector_search.tsx new file mode 100644 index 000000000000..84f86e6868d1 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/vector_search.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +import { AISearchWorkflow } from './ai_search_workflow'; +import { useAssetBasePath } from '../../hooks/use_asset_base_path'; + +export const VectorSearch: React.FC = () => { + const assetBasePath = useAssetBasePath(); + + const vectorSearchText = { + image: `${assetBasePath}/vector_search.svg`, + imageAlt: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch.imageAlt', { + defaultMessage: 'Vector search', + }), + heading: i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch.title', { + defaultMessage: 'Store and search your vector embeddings', + }), + subheading: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.vectorSearch.description', + { + defaultMessage: + 'Use Elasticsearch as a datastore for vector embeddings and enable lightning-fast searches and insights.', + } + ), + featureBullets: [ + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch.firstLine', { + defaultMessage: 'A single solution to generate, store and search your vector embeddings.', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch.secondLine', { + defaultMessage: 'Utilize the dense_vector field type for approximate kNN searches.', + }), + i18n.translate('xpack.searchHomepage.aiSearchCapabilities.vectorSearch.thirdLine', { + defaultMessage: 'Choose from several memory quantization strategies to reduce bloat.', + }), + ], + buttonLabel: i18n.translate( + 'xpack.searchHomepage.aiSearchCapabilities.vectorSearch.createVectorIndex', + { + defaultMessage: 'Create a vector optimized index', + } + ), + dataTestSubj: 'createVectorIndexButton', + }; + + return ; +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/workflow_feature_bullet.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/workflow_feature_bullet.tsx new file mode 100644 index 000000000000..fe7be5c1167c --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/ai_search_capabilities/workflow_feature_bullet.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiText, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; + +export const WorkflowFeatureBullet = ({ feature }: { feature: string }) => ( + + + + + + +

{feature}

+
+
+
+); diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/alternate_solutions.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/alternate_solutions.tsx new file mode 100644 index 000000000000..1076a73cb7dc --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/alternate_solutions.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + useCurrentEuiBreakpoint, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { Observability } from './observability'; + +export const AlternateSolutions: React.FC = () => { + const currentBreakpoint = useCurrentEuiBreakpoint(); + + return ( + <> + +

+ {i18n.translate('xpack.searchHomepage.threatDetectionSolutions.title', { + defaultMessage: 'Looking for logs or threat detection solutions?', + })} +

+
+ + + + + + {/* TO DO: Enable the following once we have text content ready + + + */} + + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/observability.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/observability.tsx new file mode 100644 index 000000000000..e92dc052fe40 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/observability.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiAvatar, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiSpacer, + EuiText, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useMemo } from 'react'; +import { useKibana } from '../../hooks/use_kibana'; +import { docLinks } from '../../../common/doc_links'; + +export const Observability: React.FC = () => { + const { euiTheme } = useEuiTheme(); + const { http, cloud } = useKibana().services; + + const o11yTrialLink = useMemo(() => { + if (cloud && cloud.isServerlessEnabled) { + const baseUrl = cloud?.projectsUrl ?? 'https://cloud.elastic.co/projects/'; + return `${baseUrl}create/observability/start`; + } + return http.basePath.prepend('/app/observability/onboarding'); + }, [cloud, http]); + + return ( + + + + + + + + +

+ {i18n.translate('xpack.searchHomepage.observability.title', { + defaultMessage: 'Observability', + })} +

+
+
+ + + + {i18n.translate('xpack.searchHomepage.observability.description', { + defaultMessage: + 'Consolidate your logs, metrics, application traces, and system availability with purpose-built UIs.', + })} + + + + + + + + + + + + + + {i18n.translate('xpack.searchHomepage.observability.logsTitle', { + defaultMessage: 'Collect and analyze logs', + })} + + + + + + {i18n.translate('xpack.searchHomepage.observability.exploreLogstashBeats', { + defaultMessage: 'Explore Logstash and Beats', + })} + + + + + + + + + + {i18n.translate( + 'xpack.searchHomepage.observability.performanceMonitoringTitle', + { + defaultMessage: 'Powerful performance monitoring', + } + )} + + + + + + {i18n.translate('xpack.searchHomepage.observability.observabilitySpaceLink', { + defaultMessage: 'Create an Observability project', + })} + + + + + + +
+
+
+ ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/security.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/security.tsx new file mode 100644 index 000000000000..99bdc9ba6288 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/alternate_solutions/security.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiSpacer, + EuiLink, + EuiAvatar, + useEuiTheme, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const Security: React.FC = () => { + const { euiTheme } = useEuiTheme(); + + return ( + + + + + + + + + + {i18n.translate('xpack.searchHomepage.security.title', { + defaultMessage: 'Security', + })} + + + + + + + {i18n.translate('xpack.searchHomepage.security.description', { + defaultMessage: + 'Prevent, collect, detect, and respond to threats for unified protection across your infrastructure.', + })} + + + + + + + + + + + + + + {i18n.translate('xpack.searchHomepage.security.detectThreatsTitle', { + defaultMessage: 'Detect threats in your data', + })} + + + + + + {i18n.translate('xpack.searchHomepage.security.setupSiem', { + defaultMessage: 'Setup your SIEM', + })} + + + + + + + + + + {i18n.translate('xpack.searchHomepage.security.secureCloudAssetsTitle', { + defaultMessage: 'Secure your cloud assets', + })} + + + + + + {i18n.translate( + 'xpack.searchHomepage.security.cloudSecurityPostureManagementLink', + { + defaultMessage: 'Cloud Security Posture Management', + } + )} + + + + + + + + + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch.tsx new file mode 100644 index 000000000000..5168be4a3b6f --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch.tsx @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiBadge, + EuiButton, + EuiButtonEmpty, + EuiButtonIcon, + EuiCopy, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { ConnectToElasticsearchSidePanel } from './connect_to_elasticsearch_side_panel'; +import { AISearchCapabilities } from './ai_search_capabilities/ai_search_capabilities'; +import { useKibana } from '../hooks/use_kibana'; +import { useGetApiKeys } from '../hooks/api/use_api_key'; +import { useElasticsearchUrl } from '../hooks/use_elasticsearch_url'; + +export const ConnectToElasticsearch = () => { + const { share } = useKibana().services; + const { data } = useGetApiKeys(); + const elasticsearchUrl = useElasticsearchUrl(); + const locator = share?.url?.locators.get('MANAGEMENT_APP_LOCATOR'); + const manageKeysLink = locator?.useUrl({ sectionId: 'security', appId: 'api_keys' }); + const createApiKeyLink = locator?.useUrl({ sectionId: 'security', appId: 'api_keys/create' }); + + return ( + + + + + + + +

+ {i18n.translate('xpack.searchHomepage.connectToElasticsearch.title', { + defaultMessage: 'Connect to Elasticsearch', + })} +

+
+
+ + +

+ {i18n.translate('xpack.searchHomepage.connectToElasticsearch.description', { + defaultMessage: + 'Set up your connection to Elasticsearch to start searching and analyzing your data.', + })} +

+
+
+
+
+ + + + + + + + {i18n.translate( + 'xpack.searchHomepage.connectToElasticsearch.elasticSearchEndpointLabel', + { + defaultMessage: 'Elasticsearch endpoint', + } + )} + + + + + + + + {(copy) => ( + + )} + + + + + + + + + + + + + + + {i18n.translate( + 'xpack.searchHomepage.connectToElasticsearch.apiKeysLabel', + { + defaultMessage: 'API keys', + } + )} + + + + + + + + {i18n.translate( + 'xpack.searchHomepage.connectToElasticsearch.createApiKey', + { + defaultMessage: 'Create API key', + } + )} + + + + + Manage API keys + + + + 0 ? 'success' : 'warning'} + > + {data?.apiKeys?.length ?? 0} active + + + + + + + + + + + + + + +
+
+ + + +
+ ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch_side_panel.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch_side_panel.tsx new file mode 100644 index 000000000000..a1bb53c5ef1f --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/connect_to_elasticsearch_side_panel.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback } from 'react'; +import { EuiCard, EuiButtonEmpty, EuiFlexGroup, EuiLink, EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useKibana } from '../hooks/use_kibana'; +import { docLinks } from '../../common/doc_links'; + +export const ConnectToElasticsearchSidePanel = () => { + const { application } = useKibana().services; + + const onFileUpload = useCallback(() => { + application.navigateToApp('ml', { path: 'filedatavisualizer' }); + }, [application]); + + return ( + + + + } + footer={ + + {i18n.translate('xpack.searchHomepage.connectToElasticsearch.uploadFileButton', { + defaultMessage: 'Upload a file', + })} + + } + /> + + {/* TODO: Enable The “Sample Data” section when the one-click sample data ingestion feature is complete. */} + {/* + } + description={ + + } + footer={ + + {i18n.translate('xpack.searchHomepage.connectToElasticsearch.sampleDatasetButton', { + defaultMessage: 'Add sample data', + })} + + } + /> */} + + } + description={ + + } + footer={ + + {i18n.translate( + 'xpack.searchHomepage.connectToElasticsearch.customerEngineerRequestForm', + { + defaultMessage: 'Submit a request', + } + )} + + } + /> + + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/console_link_button.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/console_link_button.tsx deleted file mode 100644 index b65d41a24d8d..000000000000 --- a/x-pack/solutions/search/plugins/search_homepage/public/components/console_link_button.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useCallback } from 'react'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { ConsolePluginStart } from '@kbn/console-plugin/public'; - -import { useKibana } from '../hooks/use_kibana'; -import { useUsageTracker } from '../hooks/use_usage_tracker'; - -const canOpenConsole = (plugin?: ConsolePluginStart): boolean => { - if (!plugin) return false; - if (!plugin.isEmbeddedConsoleAvailable || !plugin.openEmbeddedConsole) return false; - return plugin.isEmbeddedConsoleAvailable(); -}; - -export const ConsoleLinkButton = () => { - const { - services: { console: consolePlugin }, - } = useKibana(); - const usageTracker = useUsageTracker(); - const openConsole = useCallback(() => { - usageTracker.click('get_started_in_console'); - if (!canOpenConsole(consolePlugin)) return; - - consolePlugin!.openEmbeddedConsole!(); - }, [consolePlugin, usageTracker]); - if (consolePlugin === undefined || consolePlugin.openEmbeddedConsole === undefined) return null; - - return ( - - - - ); -}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/dive_deeper_with_elasticsearch.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/dive_deeper_with_elasticsearch.tsx new file mode 100644 index 000000000000..0e7b24d40e15 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/dive_deeper_with_elasticsearch.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTitle, + useCurrentEuiBreakpoint, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { docLinks } from '../../../common/doc_links'; +import { DocCallouts } from './doc_callouts'; + +export const DiveDeeperWithElasticsearch: React.FC = () => { + const currentBreakpoint = useCurrentEuiBreakpoint(); + return ( + <> + +

+ {i18n.translate('xpack.searchHomepage.diveDeeper.title', { + defaultMessage: 'Dive deeper with Elasticsearch', + })} +

+
+ + + + + + + + + + + + + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/doc_callouts.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/doc_callouts.tsx new file mode 100644 index 000000000000..b5eae89306c8 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/dive_deeper/doc_callouts.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiButton, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; + +export interface DocCalloutsProps { + title: string; + description: string; + buttonHref: string; + buttonLabel: string; + dataTestSubj: string; +} + +export const DocCallouts: React.FC = ({ + title, + description, + buttonHref, + buttonLabel, + dataTestSubj, +}) => { + return ( + <> + +

{title}

+
+ + + +

{description}

+
+ + + + {buttonLabel} + + + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/endpoints_header_action.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/endpoints_header_action.tsx deleted file mode 100644 index 408b0d2763df..000000000000 --- a/x-pack/solutions/search/plugins/search_homepage/public/components/endpoints_header_action.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React, { useState, useCallback } from 'react'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlyout, EuiHeaderLinks } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { - KibanaWiredConnectionDetailsProvider, - ConnectionDetailsFlyoutContent, -} from '@kbn/cloud/connection_details'; - -import { useUsageTracker } from '../hooks/use_usage_tracker'; - -export const EndpointsHeaderAction = () => { - const usageTracker = useUsageTracker(); - const [open, setOpen] = useState(false); - const onClickEndpointsButton = useCallback(() => { - usageTracker.click('endpoints_and_api_keys'); - setOpen(true); - }, [usageTracker]); - - return ( - <> - - - - - - - - {open && ( - setOpen(false)} size="s"> - - - - - )} - - ); -}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/feature_update_group.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/feature_update_group.tsx new file mode 100644 index 000000000000..09c7ba331eb5 --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/feature_update_group.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; + +interface FeatureUpdateGroupProps { + updates: string[]; +} + +export const FeatureUpdateGroup: React.FC = ({ updates }) => { + return ( + + {updates.map((update, index) => ( + + + + + + {update} + + + ))} + + ); +}; diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/footer/footer.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/footer/footer.tsx new file mode 100644 index 000000000000..cc6243c5883e --- /dev/null +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/footer/footer.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { docLinks } from '../../../common/doc_links'; + +export const Footer: React.FC = () => ( + <> + + + + {i18n.translate('xpack.searchHomepage.footer.elasticCommunity', { + defaultMessage: 'Connect with the Elastic Community', + })} + + + + + {i18n.translate('xpack.searchHomepage.footer.giveFeedback', { + defaultMessage: 'Give feedback', + })} + + + + + +); diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage.tsx index 76f34caad0a5..d3cf444cbb81 100644 --- a/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage.tsx +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage.tsx @@ -5,10 +5,10 @@ * 2.0. */ +import { EuiHorizontalRule, EuiPageTemplate } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { EuiPageTemplate } from '@elastic/eui'; - import { useKibana } from '../hooks/use_kibana'; +import { useSearchHomePageRedirect } from '../hooks/use_search_home_page_redirect'; import { SearchHomepageBody } from './search_homepage_body'; import { SearchHomepageHeader } from './search_homepage_header'; @@ -17,6 +17,8 @@ export const SearchHomepagePage = () => { services: { console: consolePlugin }, } = useKibana(); + useSearchHomePageRedirect(); + const embeddableConsole = useMemo( () => (consolePlugin?.EmbeddableConsole ? : null), [consolePlugin] @@ -24,7 +26,8 @@ export const SearchHomepagePage = () => { return ( - + + {embeddableConsole} diff --git a/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage_body.tsx b/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage_body.tsx index f27da2346871..8f75b1167cfa 100644 --- a/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage_body.tsx +++ b/x-pack/solutions/search/plugins/search_homepage/public/components/search_homepage_body.tsx @@ -6,15 +6,36 @@ */ import React from 'react'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; -import { ConsoleLinkButton } from './console_link_button'; +import { ConnectToElasticsearch } from './connect_to_elasticsearch'; +import { AlternateSolutions } from './alternate_solutions/alternate_solutions'; +import { DiveDeeperWithElasticsearch } from './dive_deeper/dive_deeper_with_elasticsearch'; +import { Footer } from './footer/footer'; export const SearchHomepageBody = () => ( - - - + + + + + + + + + + + + + + + + + + + + +