diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 690698e02a142..e06b53da0ab57 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -716,6 +716,7 @@ packages/kbn-search-connectors @elastic/search-kibana
x-pack/plugins/search_connectors @elastic/search-kibana
packages/kbn-search-errors @elastic/kibana-data-discovery
examples/search_examples @elastic/kibana-data-discovery
+x-pack/plugins/search_homepage @elastic/search-kibana
packages/kbn-search-index-documents @elastic/search-kibana
x-pack/plugins/search_inference_endpoints @elastic/search-kibana
x-pack/plugins/search_notebooks @elastic/search-kibana
diff --git a/config/serverless.es.yml b/config/serverless.es.yml
index 531fa5520c0ae..a170cf569b54d 100644
--- a/config/serverless.es.yml
+++ b/config/serverless.es.yml
@@ -69,3 +69,6 @@ xpack.searchInferenceEndpoints.ui.enabled: false
# Search Notebooks
xpack.search.notebooks.catalog.url: https://elastic-enterprise-search.s3.us-east-2.amazonaws.com/serverless/catalog.json
+
+# Search Homepage
+xpack.search.homepage.ui.enabled: true
diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc
index f78070b9bfa49..fc15206bd284d 100644
--- a/docs/developer/plugin-list.asciidoc
+++ b/docs/developer/plugin-list.asciidoc
@@ -789,6 +789,10 @@ It uses Chromium and Puppeteer underneath to run the browser in headless mode.
|This plugin contains common assets and endpoints for the use of connectors in Kibana. Primarily used by the enterprise_search and serverless_search plugins.
+|{kib-repo}blob/{branch}/x-pack/plugins/search_homepage/README.mdx[searchHomepage]
+|The Search Homepage is a shared homepage for elasticsearch users.
+
+
|{kib-repo}blob/{branch}/x-pack/plugins/search_inference_endpoints/README.md[searchInferenceEndpoints]
|The Inference Endpoints is a tool used to manage inference endpoints
diff --git a/package.json b/package.json
index 48abd4ddd30b7..efd020e91df66 100644
--- a/package.json
+++ b/package.json
@@ -727,6 +727,7 @@
"@kbn/search-connectors-plugin": "link:x-pack/plugins/search_connectors",
"@kbn/search-errors": "link:packages/kbn-search-errors",
"@kbn/search-examples-plugin": "link:examples/search_examples",
+ "@kbn/search-homepage": "link:x-pack/plugins/search_homepage",
"@kbn/search-index-documents": "link:packages/kbn-search-index-documents",
"@kbn/search-inference-endpoints": "link:x-pack/plugins/search_inference_endpoints",
"@kbn/search-notebooks": "link:x-pack/plugins/search_notebooks",
diff --git a/packages/deeplinks/search/constants.ts b/packages/deeplinks/search/constants.ts
index 36d31d22dfe21..3fdcc78bb68a1 100644
--- a/packages/deeplinks/search/constants.ts
+++ b/packages/deeplinks/search/constants.ts
@@ -17,3 +17,4 @@ export const SERVERLESS_ES_APP_ID = 'serverlessElasticsearch';
export const SERVERLESS_ES_CONNECTORS_ID = 'serverlessConnectors';
export const SERVERLESS_ES_SEARCH_PLAYGROUND_ID = 'searchPlayground';
export const SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID = 'searchInferenceEndpoints';
+export const SEARCH_HOMEPAGE = 'searchHomepage';
diff --git a/packages/deeplinks/search/deep_links.ts b/packages/deeplinks/search/deep_links.ts
index 8eeceff8f8ca2..f004d1b2c9dd6 100644
--- a/packages/deeplinks/search/deep_links.ts
+++ b/packages/deeplinks/search/deep_links.ts
@@ -17,6 +17,7 @@ import {
ENTERPRISE_SEARCH_WORKPLACESEARCH_APP_ID,
SERVERLESS_ES_SEARCH_PLAYGROUND_ID,
SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID,
+ SEARCH_HOMEPAGE,
} from './constants';
export type EnterpriseSearchApp = typeof ENTERPRISE_SEARCH_APP_ID;
@@ -29,6 +30,7 @@ export type ServerlessSearchApp = typeof SERVERLESS_ES_APP_ID;
export type ConnectorsId = typeof SERVERLESS_ES_CONNECTORS_ID;
export type SearchPlaygroundId = typeof SERVERLESS_ES_SEARCH_PLAYGROUND_ID;
export type SearchInferenceEndpointsId = typeof SERVERLESS_ES_SEARCH_INFERENCE_ENDPOINTS_ID;
+export type SearchHomepage = typeof SEARCH_HOMEPAGE;
export type ContentLinkId = 'searchIndices' | 'connectors' | 'webCrawlers';
@@ -47,6 +49,7 @@ export type DeepLinkId =
| ConnectorsId
| SearchPlaygroundId
| SearchInferenceEndpointsId
+ | SearchHomepage
| `${EnterpriseSearchContentApp}:${ContentLinkId}`
| `${EnterpriseSearchApplicationsApp}:${ApplicationsLinkId}`
| `${EnterpriseSearchAppsearchApp}:${AppsearchLinkId}`;
diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index 336cfd2c6b93d..c3ffc507387b8 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -132,6 +132,7 @@ pageLoadAssetSize:
screenshotMode: 17856
screenshotting: 22870
searchConnectors: 30000
+ searchHomepage: 19831
searchInferenceEndpoints: 20470
searchNotebooks: 18942
searchPlayground: 19325
diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts
index 31e0a44b9e823..19eeef57ba62b 100644
--- a/test/plugin_functional/test_suites/core_plugins/rendering.ts
+++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts
@@ -313,8 +313,9 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
// 'xpack.reporting.poll.jobsRefresh.intervalErrorMultiplier (number)',
'xpack.rollup.ui.enabled (boolean)',
'xpack.saved_object_tagging.cache_refresh_interval (duration)',
- 'xpack.searchPlayground.ui.enabled (boolean)',
+ 'xpack.search.homepage.ui.enabled (boolean)',
'xpack.searchInferenceEndpoints.ui.enabled (boolean)',
+ 'xpack.searchPlayground.ui.enabled (boolean)',
'xpack.security.loginAssistanceMessage (string)',
'xpack.security.sameSiteCookies (alternatives)',
'xpack.security.showInsecureClusterWarning (boolean)',
diff --git a/tsconfig.base.json b/tsconfig.base.json
index ea18fe456af85..0f8d9a11563e0 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -1426,6 +1426,8 @@
"@kbn/search-errors/*": ["packages/kbn-search-errors/*"],
"@kbn/search-examples-plugin": ["examples/search_examples"],
"@kbn/search-examples-plugin/*": ["examples/search_examples/*"],
+ "@kbn/search-homepage": ["x-pack/plugins/search_homepage"],
+ "@kbn/search-homepage/*": ["x-pack/plugins/search_homepage/*"],
"@kbn/search-index-documents": ["packages/kbn-search-index-documents"],
"@kbn/search-index-documents/*": ["packages/kbn-search-index-documents/*"],
"@kbn/search-inference-endpoints": ["x-pack/plugins/search_inference_endpoints"],
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index 2943af3cf46d5..1f224ca164e52 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -92,6 +92,7 @@
"xpack.rollupJobs": ["plugins/rollup"],
"xpack.runtimeFields": "plugins/runtime_fields",
"xpack.screenshotting": "plugins/screenshotting",
+ "xpack.searchHomepage": "plugins/search_homepage",
"xpack.searchNotebooks": "plugins/search_notebooks",
"xpack.searchPlayground": "plugins/search_playground",
"xpack.searchInferenceEndpoints": "plugins/search_inference_endpoints",
diff --git a/x-pack/plugins/enterprise_search/kibana.jsonc b/x-pack/plugins/enterprise_search/kibana.jsonc
index 3855fd3d9e1f9..0dc2562ff2fe3 100644
--- a/x-pack/plugins/enterprise_search/kibana.jsonc
+++ b/x-pack/plugins/enterprise_search/kibana.jsonc
@@ -30,6 +30,7 @@
"guidedOnboarding",
"console",
"searchConnectors",
+ "searchHomepage",
"searchPlayground",
"searchInferenceEndpoints",
"embeddable",
diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
index cca5523ded681..5f4774be15b96 100644
--- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts
@@ -45,6 +45,7 @@ export const mockKibanaValues = {
history: mockHistory,
indexMappingComponent: null,
isCloud: false,
+ isSearchHomepageEnabled: false,
isSidebarEnabled: true,
lens: {
EmbeddableComponent: jest.fn(),
@@ -64,6 +65,7 @@ export const mockKibanaValues = {
hasWebCrawler: true,
},
renderHeaderActions: jest.fn(),
+ searchHomepage: null,
searchInferenceEndpoints: null,
searchPlayground: searchPlaygroundMock.createStart(),
security: securityMock.createStart(),
diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx
index ea45e121470e2..98d6677c35fc1 100644
--- a/x-pack/plugins/enterprise_search/public/applications/index.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx
@@ -117,6 +117,7 @@ export const renderApp = (
guidedOnboarding,
history,
indexMappingComponent,
+ isSearchHomepageEnabled: plugins.searchHomepage?.isHomepageFeatureEnabled() ?? false,
isSidebarEnabled,
lens,
ml,
@@ -127,6 +128,7 @@ export const renderApp = (
params.setHeaderActionMenu(
HeaderActions ? renderHeaderActions.bind(null, HeaderActions, store, params) : undefined
),
+ searchHomepage: plugins.searchHomepage,
searchPlayground: plugins.searchPlayground,
searchInferenceEndpoints: plugins.searchInferenceEndpoints,
security,
diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx
new file mode 100644
index 0000000000000..c44cc39c5eb1d
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.test.tsx
@@ -0,0 +1,28 @@
+/*
+ * 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 { TestHelper } from '../../../test_helpers/test_utils.test_helper';
+
+import { SearchHomepagePageTemplate } from './page_template';
+
+describe('SearchHomepagePageTemplate', () => {
+ beforeAll(() => {
+ TestHelper.prepare();
+ });
+
+ it('renders as expected', async () => {
+ const { container } = TestHelper.render(
+
+ Test
+
+ );
+
+ expect(container.querySelector('.kbnSolutionNav__title')).toHaveTextContent('Search');
+ });
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.tsx
new file mode 100644
index 0000000000000..76f2e6e526239
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/layout/page_template.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 from 'react';
+
+import { SEARCH_PRODUCT_NAME } from '../../../../../common/constants';
+import { SetSearchChrome } from '../../../shared/kibana_chrome';
+import { EnterpriseSearchPageTemplateWrapper, PageTemplateProps } from '../../../shared/layout';
+import { useEnterpriseSearchNav } from '../../../shared/layout';
+import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry';
+
+export const SearchHomepagePageTemplate: React.FC = ({
+ children,
+ pageChrome,
+ pageViewTelemetry,
+ ...pageTemplateProps
+}) => {
+ return (
+ }
+ >
+ {pageViewTelemetry && (
+
+ )}
+ {children}
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.tsx
new file mode 100644
index 0000000000000..a605010fcb00d
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/components/search_homepage.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 { useValues } from 'kea';
+
+import { KibanaLogic } from '../../shared/kibana';
+import { SetSearchChrome } from '../../shared/kibana_chrome';
+
+import { SearchHomepagePageTemplate } from './layout/page_template';
+
+export const SearchHomepagePage = () => {
+ const { isSearchHomepageEnabled, searchHomepage } = useValues(KibanaLogic);
+
+ if (!isSearchHomepageEnabled || !searchHomepage) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx b/x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx
new file mode 100644
index 0000000000000..43963f21d3b5d
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/index.tsx
@@ -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 React from 'react';
+
+import { Routes, Route } from '@kbn/shared-ux-router';
+
+import { isVersionMismatch } from '../../../common/is_version_mismatch';
+import type { InitialAppData } from '../../../common/types';
+import { VersionMismatchPage } from '../shared/version_mismatch';
+
+import { SearchHomepagePage } from './components/search_homepage';
+
+export const SearchHomepage: React.FC = (props) => {
+ const { enterpriseSearchVersion, kibanaVersion } = props;
+ const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion);
+
+ const showView = () => {
+ if (incompatibleVersions) {
+ return (
+
+ );
+ }
+
+ return ;
+ };
+
+ return (
+
+
+ {showView()}
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js
new file mode 100644
index 0000000000000..c18a3561afb65
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/search_homepage/jest.config.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+module.exports = {
+ preset: '@kbn/test',
+ rootDir: '../../../../../..',
+ roots: ['/x-pack/plugins/enterprise_search/public/applications/search_homepage'],
+ collectCoverage: true,
+ coverageReporters: ['text', 'html'],
+ collectCoverageFrom: [
+ '/x-pack/plugins/enterprise_search/public/applications/**/*.{ts,tsx}',
+ '!/x-pack/plugins/enterprise_search/public/*.ts',
+ '!/x-pack/plugins/enterprise_search/server/*.ts',
+ '!/x-pack/plugins/enterprise_search/public/applications/test_helpers/**/*.{ts,tsx}',
+ ],
+ coverageDirectory:
+ '/target/kibana-coverage/jest/x-pack/plugins/enterprise_search/public/applications/search_homepage',
+ modulePathIgnorePatterns: [
+ '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress',
+ '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress',
+ ],
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
index da18e9e8bb44f..4920b25cffd75 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts
@@ -29,6 +29,7 @@ import { LensPublicStart } from '@kbn/lens-plugin/public';
import { MlPluginStart } from '@kbn/ml-plugin/public';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants';
import { ConnectorDefinition } from '@kbn/search-connectors-plugin/public';
+import type { SearchHomepagePluginStart } from '@kbn/search-homepage/public';
import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public';
import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public';
import { AuthenticatedUser, SecurityPluginStart } from '@kbn/security-plugin/public';
@@ -58,6 +59,7 @@ export interface KibanaLogicProps {
guidedOnboarding?: GuidedOnboardingPluginStart;
history: ScopedHistory;
indexMappingComponent?: React.FC;
+ isSearchHomepageEnabled: boolean;
isSidebarEnabled: boolean;
lens?: LensPublicStart;
ml?: MlPluginStart;
@@ -65,6 +67,7 @@ export interface KibanaLogicProps {
productAccess: ProductAccess;
productFeatures: ProductFeatures;
renderHeaderActions(HeaderActions?: FC): void;
+ searchHomepage?: SearchHomepagePluginStart;
searchPlayground?: SearchPlaygroundPluginStart;
searchInferenceEndpoints?: SearchInferenceEndpointsPluginStart;
security?: SecurityPluginStart;
@@ -91,6 +94,7 @@ export interface KibanaValues {
history: ScopedHistory;
indexMappingComponent: React.FC | null;
isCloud: boolean;
+ isSearchHomepageEnabled: boolean;
isSidebarEnabled: boolean;
lens: LensPublicStart | null;
ml: MlPluginStart | null;
@@ -98,6 +102,7 @@ export interface KibanaValues {
productAccess: ProductAccess;
productFeatures: ProductFeatures;
renderHeaderActions(HeaderActions?: FC): void;
+ searchHomepage: SearchHomepagePluginStart | null;
searchPlayground: SearchPlaygroundPluginStart | null;
searchInferenceEndpoints: SearchInferenceEndpointsPluginStart | null;
security: SecurityPluginStart | null;
@@ -129,6 +134,7 @@ export const KibanaLogic = kea>({
guidedOnboarding: [props.guidedOnboarding || null, {}],
history: [props.history, {}],
indexMappingComponent: [props.indexMappingComponent || null, {}],
+ isSearchHomepageEnabled: [props.isSearchHomepageEnabled, {}],
isSidebarEnabled: [props.isSidebarEnabled, {}],
lens: [props.lens || null, {}],
ml: [props.ml || null, {}],
@@ -143,6 +149,7 @@ export const KibanaLogic = kea>({
productAccess: [props.productAccess, {}],
productFeatures: [props.productFeatures, {}],
renderHeaderActions: [props.renderHeaderActions, {}],
+ searchHomepage: [props.searchHomepage || null, {}],
searchPlayground: [props.searchPlayground || null, {}],
searchInferenceEndpoints: [props.searchInferenceEndpoints || null, {}],
security: [props.security || null, {}],
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts
new file mode 100644
index 0000000000000..34e9e12c88b76
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/breadcrumbs_home.ts
@@ -0,0 +1,18 @@
+/*
+ * 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 { ENTERPRISE_SEARCH_OVERVIEW_PLUGIN } from '../../../../common/constants';
+
+/**
+ * HACK for base homepage URL, this can be removed and updated to a static
+ * URL when Search Homepage is no longer feature flagged.
+ */
+const breadCrumbHome = { url: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL };
+export const getHomeURL = () => breadCrumbHome.url;
+export const setBreadcrumbHomeUrl = (url: string) => {
+ breadCrumbHome.url = url;
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts
index ac3e6d7a6437d..5798a48680d1f 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts
@@ -15,7 +15,6 @@ import {
APP_SEARCH_PLUGIN,
ENTERPRISE_SEARCH_CONTENT_PLUGIN,
INFERENCE_ENDPOINTS_PLUGIN,
- ENTERPRISE_SEARCH_OVERVIEW_PLUGIN,
ENTERPRISE_SEARCH_PRODUCT_NAME,
AI_SEARCH_PLUGIN,
SEARCH_EXPERIENCES_PLUGIN,
@@ -29,6 +28,8 @@ import { HttpLogic } from '../http';
import { KibanaLogic } from '../kibana';
import { letBrowserHandleEvent, createHref } from '../react_router_helpers';
+import { getHomeURL } from './breadcrumbs_home';
+
/**
* Types
*/
@@ -107,7 +108,7 @@ export const useSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) =>
useEuiBreadcrumbs([
{
text: SEARCH_PRODUCT_NAME,
- path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
+ path: getHomeURL(),
shouldNotCreateHref: true,
},
...breadcrumbs,
@@ -117,7 +118,7 @@ export const useEnterpriseSearchBreadcrumbs = (breadcrumbs: Breadcrumbs = []) =>
useEuiBreadcrumbs([
{
text: ENTERPRISE_SEARCH_PRODUCT_NAME,
- path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
+ path: getHomeURL(),
shouldNotCreateHref: true,
},
...breadcrumbs,
diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx
index bd53ed235d4cb..77454581c61e7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx
@@ -49,7 +49,8 @@ import { generateNavLink } from './nav_link_helpers';
* @returns The Enterprise Search navigation items
*/
export const useEnterpriseSearchNav = (alwaysReturn = false) => {
- const { isSidebarEnabled, productAccess } = useValues(KibanaLogic);
+ const { isSearchHomepageEnabled, searchHomepage, isSidebarEnabled, productAccess } =
+ useValues(KibanaLogic);
const indicesNavItems = useIndicesNav();
if (!isSidebarEnabled && !alwaysReturn) return undefined;
@@ -66,7 +67,10 @@ export const useEnterpriseSearchNav = (alwaysReturn = false) => {
...generateNavLink({
shouldNotCreateHref: true,
shouldShowActiveForSubroutes: true,
- to: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
+ to:
+ isSearchHomepageEnabled && searchHomepage
+ ? searchHomepage.app.appRoute
+ : ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
}),
},
{
diff --git a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx
index 5601c006a4433..0050165b8be50 100644
--- a/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/test_helpers/test_utils.test_helper.tsx
@@ -62,6 +62,7 @@ export const mockKibanaProps: KibanaLogicProps = {
indexMappingComponent: () => {
return <>>;
},
+ isSearchHomepageEnabled: false,
isSidebarEnabled: true,
lens: {
EmbeddableComponent: jest.fn(),
@@ -84,6 +85,7 @@ export const mockKibanaProps: KibanaLogicProps = {
hasWebCrawler: true,
},
renderHeaderActions: jest.fn(),
+ searchHomepage: undefined,
searchPlayground: searchPlaygroundMock.createStart(),
security: securityMock.createStart(),
setBreadcrumbs: jest.fn(),
@@ -114,7 +116,7 @@ interface TestHelper {
defaultMockValues: typeof DEFAULT_VALUES;
mountLogic: (logicFile: LogicFile, props?: object) => void;
prepare: (options?: PrepareOptions) => void;
- render: (children: JSX.Element) => void;
+ render: (children: JSX.Element) => ReturnType;
}
export const TestHelper: TestHelper = {
@@ -147,7 +149,7 @@ export const TestHelper: TestHelper = {
TestHelper.actionsToRun.forEach((action) => {
action();
});
- testingLibraryRender(
+ return testingLibraryRender(
{children}
diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts
index dc079aec90688..051cfaa6779af 100644
--- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts
+++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts
@@ -67,12 +67,14 @@ const euiItemTypeToNodeDefinition = ({
export const getNavigationTreeDefinition = ({
dynamicItems$,
+ isSearchHomepageEnabled,
}: {
dynamicItems$: Observable;
+ isSearchHomepageEnabled: boolean;
}): AddSolutionNavigationArg => {
return {
dataTestSubj: 'searchSideNav',
- homePage: 'enterpriseSearch',
+ homePage: isSearchHomepageEnabled ? 'searchHomepage' : 'enterpriseSearch',
icon,
id: 'es',
navigationTree$: dynamicItems$.pipe(
@@ -84,7 +86,7 @@ export const getNavigationTreeDefinition = ({
breadcrumbStatus: 'hidden',
children: [
{
- link: 'enterpriseSearch',
+ link: isSearchHomepageEnabled ? 'searchHomepage' : 'enterpriseSearch',
},
{
getIsActive: ({ pathNameSerialized, prepend }) => {
diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts
index 9c03fb623fa3d..280de2f04356b 100644
--- a/x-pack/plugins/enterprise_search/public/plugin.ts
+++ b/x-pack/plugins/enterprise_search/public/plugin.ts
@@ -32,6 +32,10 @@ import { MlPluginStart } from '@kbn/ml-plugin/public';
import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '@kbn/search-api-panels/constants';
import { SearchConnectorsPluginStart } from '@kbn/search-connectors-plugin/public';
+import type {
+ SearchHomepagePluginSetup,
+ SearchHomepagePluginStart,
+} from '@kbn/search-homepage/public';
import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public';
import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public';
import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public';
@@ -67,6 +71,7 @@ import {
import { INFERENCE_ENDPOINTS_PATH } from './applications/enterprise_search_relevance/routes';
import { docLinks } from './applications/shared/doc_links';
+import { setBreadcrumbHomeUrl } from './applications/shared/kibana_chrome/breadcrumbs_home';
import type { DynamicSideNavItems } from './navigation_tree';
export interface ClientData extends InitialAppData {
@@ -80,6 +85,7 @@ export type EnterpriseSearchPublicStart = ReturnType {
- const kibanaDeps = await this.getKibanaDeps(core, params, cloud);
- const { chrome, http } = kibanaDeps.core;
- chrome.docTitle.change(ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME);
+ if (useSearchHomepage) {
+ const { app } = plugins.searchHomepage!;
+ core.application.register({
+ ...app,
+ category: DEFAULT_APP_CATEGORIES.enterpriseSearch,
+ euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO,
+ visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'],
+ mount: async (params: AppMountParameters) => {
+ const kibanaDeps = await this.getKibanaDeps(core, params, cloud);
+ const { chrome, http } = kibanaDeps.core;
+ chrome.docTitle.change(app.title);
- await this.getInitialData(http);
- const pluginData = this.getPluginData();
+ await this.getInitialData(http);
+ const pluginData = this.getPluginData();
- const { renderApp } = await import('./applications');
- const { EnterpriseSearchOverview } = await import(
- './applications/enterprise_search_overview'
- );
+ const { renderApp } = await import('./applications');
+ const { SearchHomepage } = await import('./applications/search_homepage');
- return renderApp(EnterpriseSearchOverview, kibanaDeps, pluginData);
- },
- title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE,
- visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'],
- });
+ return renderApp(SearchHomepage, kibanaDeps, pluginData);
+ },
+ });
+ setBreadcrumbHomeUrl(app.appRoute);
+ } else {
+ core.application.register({
+ appRoute: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
+ category: DEFAULT_APP_CATEGORIES.enterpriseSearch,
+ euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO,
+ id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID,
+ mount: async (params: AppMountParameters) => {
+ const kibanaDeps = await this.getKibanaDeps(core, params, cloud);
+ const { chrome, http } = kibanaDeps.core;
+ chrome.docTitle.change(ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME);
+
+ await this.getInitialData(http);
+ const pluginData = this.getPluginData();
+
+ const { renderApp } = await import('./applications');
+ const { EnterpriseSearchOverview } = await import(
+ './applications/enterprise_search_overview'
+ );
+
+ return renderApp(EnterpriseSearchOverview, kibanaDeps, pluginData);
+ },
+ title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE,
+ visibleIn: ['home', 'kibanaOverview', 'globalSearch', 'sideNav'],
+ });
+ }
core.application.register({
appRoute: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL,
@@ -512,14 +545,27 @@ export class EnterpriseSearchPlugin implements Plugin {
}
if (plugins.home) {
- plugins.home.featureCatalogue.registerSolution({
- description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION,
- icon: 'logoEnterpriseSearch',
- id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID,
- order: 100,
- path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
- title: SEARCH_PRODUCT_NAME,
- });
+ if (useSearchHomepage) {
+ const { searchHomepage } = plugins;
+
+ plugins.home.featureCatalogue.registerSolution({
+ description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION,
+ icon: 'logoEnterpriseSearch',
+ id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID,
+ order: 100,
+ path: searchHomepage!.app.appRoute,
+ title: SEARCH_PRODUCT_NAME,
+ });
+ } else {
+ plugins.home.featureCatalogue.registerSolution({
+ description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION,
+ icon: 'logoEnterpriseSearch',
+ id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID,
+ order: 100,
+ path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL,
+ title: SEARCH_PRODUCT_NAME,
+ });
+ }
plugins.home.featureCatalogue.register({
category: 'data',
@@ -587,7 +633,10 @@ export class EnterpriseSearchPlugin implements Plugin {
import('./navigation_tree').then(({ getNavigationTreeDefinition }) => {
return plugins.navigation.addSolutionNavigation(
- getNavigationTreeDefinition({ dynamicItems$: this.sideNavDynamicItems$ })
+ getNavigationTreeDefinition({
+ dynamicItems$: this.sideNavDynamicItems$,
+ isSearchHomepageEnabled: plugins.searchHomepage?.isHomepageFeatureEnabled() ?? false,
+ })
);
});
diff --git a/x-pack/plugins/enterprise_search/tsconfig.json b/x-pack/plugins/enterprise_search/tsconfig.json
index 3a66b8350be4f..a6bb797de5eb1 100644
--- a/x-pack/plugins/enterprise_search/tsconfig.json
+++ b/x-pack/plugins/enterprise_search/tsconfig.json
@@ -79,6 +79,7 @@
"@kbn/cloud",
"@kbn/try-in-console",
"@kbn/core-chrome-browser",
- "@kbn/navigation-plugin"
+ "@kbn/navigation-plugin",
+ "@kbn/search-homepage"
]
}
diff --git a/x-pack/plugins/search_homepage/README.mdx b/x-pack/plugins/search_homepage/README.mdx
new file mode 100644
index 0000000000000..00ba4f491c607
--- /dev/null
+++ b/x-pack/plugins/search_homepage/README.mdx
@@ -0,0 +1,3 @@
+# Search Homepage
+
+The Search Homepage is a shared homepage for elasticsearch users.
diff --git a/x-pack/plugins/search_homepage/common/index.ts b/x-pack/plugins/search_homepage/common/index.ts
new file mode 100644
index 0000000000000..d93d5c49f8cc5
--- /dev/null
+++ b/x-pack/plugins/search_homepage/common/index.ts
@@ -0,0 +1,14 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+export const PLUGIN_ID = 'searchHomepage';
+export const PLUGIN_NAME = 'searchHomepage';
+
+/**
+ * UI Setting id for the Search Homepage feature flag
+ */
+export const HOMEPAGE_FEATURE_FLAG_ID = 'searchHomepage:homepageEnabled';
diff --git a/x-pack/plugins/search_homepage/jest.config.js b/x-pack/plugins/search_homepage/jest.config.js
new file mode 100644
index 0000000000000..65cd8f1e34252
--- /dev/null
+++ b/x-pack/plugins/search_homepage/jest.config.js
@@ -0,0 +1,15 @@
+/*
+ * 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.
+ */
+
+module.exports = {
+ preset: '@kbn/test',
+ rootDir: '../../..',
+ roots: ['/x-pack/plugins/search_homepage'],
+ coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/search_homepage',
+ coverageReporters: ['text', 'html'],
+ collectCoverageFrom: ['/x-pack/plugins/search_homepage/{public,server}/**/*.{ts,tsx}'],
+};
diff --git a/x-pack/plugins/search_homepage/kibana.jsonc b/x-pack/plugins/search_homepage/kibana.jsonc
new file mode 100644
index 0000000000000..0e345ab0d330a
--- /dev/null
+++ b/x-pack/plugins/search_homepage/kibana.jsonc
@@ -0,0 +1,26 @@
+{
+ "type": "plugin",
+ "id": "@kbn/search-homepage",
+ "owner": "@elastic/search-kibana",
+ "plugin": {
+ "id": "searchHomepage",
+ "server": true,
+ "browser": true,
+ "configPath": [
+ "xpack",
+ "search",
+ "homepage"
+ ],
+ "requiredPlugins": [
+ "share",
+ ],
+ "optionalPlugins": [
+ "cloud",
+ "console",
+ "usageCollection",
+ ],
+ "requiredBundles": [
+ "kibanaReact"
+ ]
+ }
+}
diff --git a/x-pack/plugins/search_homepage/public/application.tsx b/x-pack/plugins/search_homepage/public/application.tsx
new file mode 100644
index 0000000000000..4af256de498ed
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/application.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 from 'react';
+import ReactDOM from 'react-dom';
+import { CoreStart } from '@kbn/core/public';
+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 { SearchHomepageAppPluginStartDependencies } from './types';
+import { HomepageRouter } from './router';
+
+export const renderApp = async (
+ core: CoreStart,
+ services: SearchHomepageAppPluginStartDependencies,
+ element: HTMLElement
+) => {
+ ReactDOM.render(
+
+
+
+
+
+
+
+
+ ,
+ element
+ );
+
+ return () => ReactDOM.unmountComponentAtNode(element);
+};
diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage.tsx
new file mode 100644
index 0000000000000..7af02cbcf3275
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/components/search_homepage.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 React, { useMemo } from 'react';
+import { EuiPageTemplate } from '@elastic/eui';
+
+import { useKibana } from '../hooks/use_kibana';
+import { SearchHomepageBody } from './search_homepage_body';
+import { SearchHomepageHeader } from './search_homepage_header';
+
+export const SearchHomepagePage = () => {
+ const {
+ services: { console: consolePlugin },
+ } = useKibana();
+
+ const embeddableConsole = useMemo(
+ () => (consolePlugin?.EmbeddableConsole ? : null),
+ [consolePlugin]
+ );
+
+ return (
+
+
+
+ {embeddableConsole}
+
+ );
+};
diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx
new file mode 100644
index 0000000000000..808393594e7d8
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/components/search_homepage_body.tsx
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import React from 'react';
+import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
+
+export const SearchHomepageBody = () => (
+
+
+
+);
diff --git a/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx b/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx
new file mode 100644
index 0000000000000..941655d67cdab
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/components/search_homepage_header.tsx
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+import React from 'react';
+import { EuiPageTemplate, EuiTitle } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n-react';
+
+export const SearchHomepageHeader = () => (
+
+
+
+
+
+ }
+ data-test-subj="search-homepage-header"
+ rightSideItems={[]}
+ />
+);
diff --git a/x-pack/plugins/search_homepage/public/components/stack_app.tsx b/x-pack/plugins/search_homepage/public/components/stack_app.tsx
new file mode 100644
index 0000000000000..ca18ac7112c09
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/components/stack_app.tsx
@@ -0,0 +1,19 @@
+/*
+ * 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 { SearchHomepageBody } from './search_homepage_body';
+import { SearchHomepageHeader } from './search_homepage_header';
+
+export const App: React.FC = () => {
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/x-pack/plugins/search_homepage/public/embeddable.tsx b/x-pack/plugins/search_homepage/public/embeddable.tsx
new file mode 100644
index 0000000000000..ee69062ea3fe5
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/embeddable.tsx
@@ -0,0 +1,12 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { dynamic } from '@kbn/shared-ux-utility';
+
+export const SearchHomepage = dynamic(async () => ({
+ default: (await import('./components/stack_app')).App,
+}));
diff --git a/x-pack/plugins/search_homepage/public/feature_flags.ts b/x-pack/plugins/search_homepage/public/feature_flags.ts
new file mode 100644
index 0000000000000..bea65a8e1548f
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/feature_flags.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.
+ */
+
+import { IUiSettingsClient } from '@kbn/core/public';
+import { HOMEPAGE_FEATURE_FLAG_ID } from '../common';
+
+export function isHomepageEnabled(uiSettings: IUiSettingsClient): boolean {
+ return uiSettings.get(HOMEPAGE_FEATURE_FLAG_ID, false);
+}
diff --git a/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts b/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts
new file mode 100644
index 0000000000000..b22c7b4ed9d7f
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/hooks/use_kibana.ts
@@ -0,0 +1,11 @@
+/*
+ * 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 { useKibana as _useKibana } from '@kbn/kibana-react-plugin/public';
+import { SearchHomepageServicesContext } from '../types';
+
+export const useKibana = () => _useKibana();
diff --git a/x-pack/plugins/search_homepage/public/index.ts b/x-pack/plugins/search_homepage/public/index.ts
new file mode 100644
index 0000000000000..b5133bb506406
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { PluginInitializerContext } from '@kbn/core/public';
+
+import { SearchHomepagePlugin } from './plugin';
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new SearchHomepagePlugin(initializerContext);
+}
+
+export type {
+ SearchHomepagePluginSetup,
+ SearchHomepagePluginStart,
+ SearchHomepageAppInfo,
+} from './types';
diff --git a/x-pack/plugins/search_homepage/public/plugin.ts b/x-pack/plugins/search_homepage/public/plugin.ts
new file mode 100644
index 0000000000000..ebb3ef8ed822c
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/plugin.ts
@@ -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 {
+ CoreSetup,
+ Plugin,
+ CoreStart,
+ AppMountParameters,
+ PluginInitializerContext,
+} from '@kbn/core/public';
+import { i18n } from '@kbn/i18n';
+import { PLUGIN_ID } from '../common';
+
+import { SearchHomepage } from './embeddable';
+import { isHomepageEnabled } from './feature_flags';
+import {
+ SearchHomepageConfigType,
+ SearchHomepagePluginSetup,
+ SearchHomepagePluginStart,
+ SearchHomepageAppPluginStartDependencies,
+ SearchHomepageAppInfo,
+} from './types';
+
+const appInfo: SearchHomepageAppInfo = {
+ id: PLUGIN_ID,
+ appRoute: '/app/elasticsearch/home',
+ title: i18n.translate('xpack.searchHomepage.appTitle', { defaultMessage: 'Home' }),
+};
+
+export class SearchHomepagePlugin
+ implements Plugin
+{
+ private readonly config: SearchHomepageConfigType;
+ constructor(initializerContext: PluginInitializerContext) {
+ this.config = initializerContext.config.get();
+ }
+
+ public setup(
+ core: CoreSetup
+ ) {
+ const result: SearchHomepagePluginSetup = {
+ app: appInfo,
+ isHomepageFeatureEnabled() {
+ return isHomepageEnabled(core.uiSettings);
+ },
+ };
+ if (!this.config.ui?.enabled) return result;
+ if (!isHomepageEnabled(core.uiSettings)) return result;
+
+ core.application.register({
+ ...result.app,
+ async mount({ element, history }: AppMountParameters) {
+ const { renderApp } = await import('./application');
+ const [coreStart, depsStart] = await core.getStartServices();
+ const startDeps: SearchHomepageAppPluginStartDependencies = {
+ ...depsStart,
+ history,
+ };
+
+ return renderApp(coreStart, startDeps, element);
+ },
+ });
+
+ return result;
+ }
+
+ public start(core: CoreStart) {
+ return {
+ app: appInfo,
+ isHomepageFeatureEnabled() {
+ return isHomepageEnabled(core.uiSettings);
+ },
+ SearchHomepage,
+ };
+ }
+}
diff --git a/x-pack/plugins/search_homepage/public/router.tsx b/x-pack/plugins/search_homepage/public/router.tsx
new file mode 100644
index 0000000000000..e4db94ebde4ae
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/router.tsx
@@ -0,0 +1,19 @@
+/*
+ * 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 { Route, Routes } from '@kbn/shared-ux-router';
+
+import { SearchHomepagePage } from './components/search_homepage';
+
+export const HomepageRouter = () => (
+
+
+
+
+
+);
diff --git a/x-pack/plugins/search_homepage/public/types.ts b/x-pack/plugins/search_homepage/public/types.ts
new file mode 100644
index 0000000000000..de5283abfc61d
--- /dev/null
+++ b/x-pack/plugins/search_homepage/public/types.ts
@@ -0,0 +1,74 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import type { ComponentProps, FC } from 'react';
+import type { CloudSetup } from '@kbn/cloud-plugin/public';
+import type { ConsolePluginStart } from '@kbn/console-plugin/public';
+import type { AppMountParameters, HttpStart } from '@kbn/core/public';
+import type { SharePluginStart } from '@kbn/share-plugin/public';
+import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
+import type { App } from './components/stack_app';
+
+export interface SearchHomepageConfigType {
+ ui: {
+ enabled: boolean;
+ };
+}
+
+export interface SearchHomepageAppInfo {
+ appRoute: string;
+ id: string;
+ title: string;
+}
+
+export interface SearchHomepagePluginSetup {
+ /**
+ * Search Homepage shared information for the Kibana application.
+ * Used to ensure the stack and serverless apps have the same route
+ * and deep links.
+ */
+ app: SearchHomepageAppInfo;
+ /**
+ * Checks if the Search Homepage feature flag is currently enabled.
+ * @returns true if Search Homepage feature is enabled
+ */
+ isHomepageFeatureEnabled: () => boolean;
+}
+
+export interface SearchHomepagePluginStart {
+ /**
+ * Search Homepage shared information for the Kibana application.
+ * Used to ensure the stack and serverless apps have the same route
+ * and deep links.
+ */
+ app: SearchHomepageAppInfo;
+ /**
+ * Checks if the Search Homepage feature flag is currently enabled.
+ * @returns true if Search Homepage feature is enabled
+ */
+ isHomepageFeatureEnabled: () => boolean;
+ /**
+ * SearchHomepage shared component, used to render the search homepage in
+ * the Stack search plugin
+ */
+ SearchHomepage: FC>;
+}
+
+export interface SearchHomepageAppPluginStartDependencies {
+ history: AppMountParameters['history'];
+ usageCollection?: UsageCollectionStart;
+ share: SharePluginStart;
+ console?: ConsolePluginStart;
+}
+
+export interface SearchHomepageServicesContext {
+ http: HttpStart;
+ share: SharePluginStart;
+ cloud?: CloudSetup;
+ usageCollection?: UsageCollectionStart;
+ console?: ConsolePluginStart;
+}
diff --git a/x-pack/plugins/search_homepage/server/config.ts b/x-pack/plugins/search_homepage/server/config.ts
new file mode 100644
index 0000000000000..3e068a719f046
--- /dev/null
+++ b/x-pack/plugins/search_homepage/server/config.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { schema, TypeOf } from '@kbn/config-schema';
+import { PluginConfigDescriptor } from '@kbn/core/server';
+
+export * from './types';
+
+const configSchema = schema.object({
+ enabled: schema.boolean({ defaultValue: true }),
+ ui: schema.object({
+ enabled: schema.boolean({ defaultValue: false }),
+ }),
+});
+
+export type SearchHomepageConfig = TypeOf;
+
+export const config: PluginConfigDescriptor = {
+ exposeToBrowser: {
+ ui: true,
+ },
+ schema: configSchema,
+};
diff --git a/x-pack/plugins/search_homepage/server/index.ts b/x-pack/plugins/search_homepage/server/index.ts
new file mode 100644
index 0000000000000..864af85c0a2fb
--- /dev/null
+++ b/x-pack/plugins/search_homepage/server/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { PluginInitializerContext } from '@kbn/core/server';
+
+export { config } from './config';
+
+export async function plugin(initializerContext: PluginInitializerContext) {
+ const { SearchHomepagePlugin } = await import('./plugin');
+ return new SearchHomepagePlugin(initializerContext);
+}
+
+export type { SearchHomepagePluginSetup, SearchHomepagePluginStart } from './types';
diff --git a/x-pack/plugins/search_homepage/server/plugin.ts b/x-pack/plugins/search_homepage/server/plugin.ts
new file mode 100644
index 0000000000000..f446ba4e41fd3
--- /dev/null
+++ b/x-pack/plugins/search_homepage/server/plugin.ts
@@ -0,0 +1,28 @@
+/*
+ * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server';
+
+import { SearchHomepagePluginSetup, SearchHomepagePluginStart } from './types';
+
+export class SearchHomepagePlugin
+ implements Plugin
+{
+ private readonly logger: Logger;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.logger = initializerContext.logger.get();
+ }
+
+ public setup(core: CoreSetup<{}, SearchHomepagePluginStart>) {
+ this.logger.debug('searchHomepage: Setup');
+ return {};
+ }
+
+ public start(core: CoreStart) {
+ return {};
+ }
+}
diff --git a/x-pack/plugins/search_homepage/server/types.ts b/x-pack/plugins/search_homepage/server/types.ts
new file mode 100644
index 0000000000000..c4e5d46959422
--- /dev/null
+++ b/x-pack/plugins/search_homepage/server/types.ts
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface SearchHomepagePluginSetup {}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface SearchHomepagePluginStart {}
diff --git a/x-pack/plugins/search_homepage/tsconfig.json b/x-pack/plugins/search_homepage/tsconfig.json
new file mode 100644
index 0000000000000..9f084b32f7d3b
--- /dev/null
+++ b/x-pack/plugins/search_homepage/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "target/types",
+ },
+ "include": [
+ "__mocks__/**/*",
+ "common/**/*",
+ "public/**/*",
+ "server/**/*",
+ ],
+ "kbn_references": [
+ "@kbn/core",
+ "@kbn/react-kibana-context-render",
+ "@kbn/kibana-react-plugin",
+ "@kbn/i18n-react",
+ "@kbn/shared-ux-router",
+ "@kbn/shared-ux-page-kibana-template",
+ "@kbn/shared-ux-utility",
+ "@kbn/i18n",
+ "@kbn/cloud-plugin",
+ "@kbn/console-plugin",
+ "@kbn/share-plugin",
+ "@kbn/usage-collection-plugin",
+ "@kbn/config-schema",
+ ],
+ "exclude": [
+ "target/**/*",
+ ]
+}
diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc
index 3a98a87c032a4..04002ee897cf4 100644
--- a/x-pack/plugins/serverless_search/kibana.jsonc
+++ b/x-pack/plugins/serverless_search/kibana.jsonc
@@ -29,6 +29,7 @@
"optionalPlugins": [
"indexManagement",
"searchConnectors",
+ "searchHomepage",
"searchInferenceEndpoints",
"usageCollection"
],
diff --git a/x-pack/plugins/serverless_search/public/navigation_tree.ts b/x-pack/plugins/serverless_search/public/navigation_tree.ts
index d21eee8de9c19..f5618e8b83e05 100644
--- a/x-pack/plugins/serverless_search/public/navigation_tree.ts
+++ b/x-pack/plugins/serverless_search/public/navigation_tree.ts
@@ -9,7 +9,7 @@ import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser';
import { i18n } from '@kbn/i18n';
import { CONNECTORS_LABEL } from '../common/i18n_string';
-export const navigationTree: NavigationTreeDefinition = {
+export const navigationTree = (useSearchHomepage: boolean = false): NavigationTreeDefinition => ({
body: [
{
type: 'navGroup',
@@ -25,7 +25,7 @@ export const navigationTree: NavigationTreeDefinition = {
title: i18n.translate('xpack.serverlessSearch.nav.home', {
defaultMessage: 'Home',
}),
- link: 'serverlessElasticsearch',
+ link: useSearchHomepage ? 'searchHomepage' : 'serverlessElasticsearch',
spaceBefore: 'm',
},
{
@@ -149,4 +149,4 @@ export const navigationTree: NavigationTreeDefinition = {
],
},
],
-};
+});
diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts
index d9019f911444a..e72e1a4575079 100644
--- a/x-pack/plugins/serverless_search/public/plugin.ts
+++ b/x-pack/plugins/serverless_search/public/plugin.ts
@@ -43,6 +43,9 @@ export class ServerlessSearchPlugin
core: CoreSetup,
setupDeps: ServerlessSearchPluginSetupDependencies
): ServerlessSearchPluginSetup {
+ const { searchHomepage } = setupDeps;
+ const useSearchHomepage = searchHomepage && searchHomepage.isHomepageFeatureEnabled();
+
const queryClient = new QueryClient({
mutationCache: new MutationCache({
onError: (error) => {
@@ -69,6 +72,24 @@ export class ServerlessSearchPlugin
},
}),
});
+ if (useSearchHomepage) {
+ core.application.register({
+ id: 'serverlessHomeRedirect',
+ title: i18n.translate('xpack.serverlessSearch.app.home.title', {
+ defaultMessage: 'Home',
+ }),
+ appRoute: '/app/elasticsearch',
+ euiIconType: 'logoElastic',
+ category: DEFAULT_APP_CATEGORIES.enterpriseSearch,
+ visibleIn: [],
+ async mount({}: AppMountParameters) {
+ const [coreStart] = await core.getStartServices();
+ coreStart.application.navigateToApp('searchHomepage');
+ return () => {};
+ },
+ });
+ }
+
core.application.register({
id: 'serverlessElasticsearch',
title: i18n.translate('xpack.serverlessSearch.app.elasticsearch.title', {
@@ -76,7 +97,7 @@ export class ServerlessSearchPlugin
}),
euiIconType: 'logoElastic',
category: DEFAULT_APP_CATEGORIES.enterpriseSearch,
- appRoute: '/app/elasticsearch',
+ appRoute: useSearchHomepage ? '/app/elasticsearch/getting_started' : '/app/elasticsearch',
async mount({ element, history }: AppMountParameters) {
const { renderApp } = await import('./application/elasticsearch');
const [coreStart, services] = await core.getStartServices();
@@ -121,10 +142,12 @@ export class ServerlessSearchPlugin
core: CoreStart,
services: ServerlessSearchPluginStartDependencies
): ServerlessSearchPluginStart {
- const { serverless, management, indexManagement, security } = services;
- serverless.setProjectHome('/app/elasticsearch');
+ const { serverless, management, indexManagement, security, searchHomepage } = services;
+ const useSearchHomepage = searchHomepage && searchHomepage.isHomepageFeatureEnabled();
+
+ serverless.setProjectHome(useSearchHomepage ? '/app/elasticsearch/home' : '/app/elasticsearch');
- const navigationTree$ = of(navigationTree);
+ const navigationTree$ = of(navigationTree(searchHomepage?.isHomepageFeatureEnabled() ?? false));
serverless.initNavigation('search', navigationTree$, { dataTestSubj: 'svlSearchSideNav' });
const extendCardNavDefinitions = serverless.getNavigationCards(
diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts
index e4eab5fbfd61d..d3011210c524f 100644
--- a/x-pack/plugins/serverless_search/public/types.ts
+++ b/x-pack/plugins/serverless_search/public/types.ts
@@ -5,16 +5,20 @@
* 2.0.
*/
-import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
-import { ConsolePluginStart } from '@kbn/console-plugin/public';
-import { SearchPlaygroundPluginStart } from '@kbn/search-playground/public';
-import { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public';
-import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public';
-import { SecurityPluginStart } from '@kbn/security-plugin/public';
-import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';
-import { SharePluginStart } from '@kbn/share-plugin/public';
-import { IndexManagementPluginStart } from '@kbn/index-management-plugin/public';
+import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
+import type { ConsolePluginStart } from '@kbn/console-plugin/public';
+import type { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public';
+import type { SearchPlaygroundPluginStart } from '@kbn/search-playground/public';
+import type { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public';
+import type { SecurityPluginStart } from '@kbn/security-plugin/public';
+import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';
+import type { SharePluginStart } from '@kbn/share-plugin/public';
+import type { IndexManagementPluginStart } from '@kbn/index-management-plugin/public';
import type { DiscoverSetup } from '@kbn/discover-plugin/public';
+import type {
+ SearchHomepagePluginSetup,
+ SearchHomepagePluginStart,
+} from '@kbn/search-homepage/public';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ServerlessSearchPluginSetup {}
@@ -27,6 +31,7 @@ export interface ServerlessSearchPluginSetupDependencies {
management: ManagementSetup;
serverless: ServerlessPluginSetup;
discover: DiscoverSetup;
+ searchHomepage?: SearchHomepagePluginSetup;
}
export interface ServerlessSearchPluginStartDependencies {
@@ -39,4 +44,5 @@ export interface ServerlessSearchPluginStartDependencies {
serverless: ServerlessPluginStart;
share: SharePluginStart;
indexManagement?: IndexManagementPluginStart;
+ searchHomepage?: SearchHomepagePluginStart;
}
diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json
index 8cf2dec121d46..418dcb5fc6f5c 100644
--- a/x-pack/plugins/serverless_search/tsconfig.json
+++ b/x-pack/plugins/serverless_search/tsconfig.json
@@ -50,5 +50,6 @@
"@kbn/react-kibana-context-render",
"@kbn/search-playground",
"@kbn/search-inference-endpoints",
+ "@kbn/search-homepage",
]
}
diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts
index f1604d48508e2..94e02f9c5e455 100644
--- a/x-pack/test_serverless/functional/page_objects/index.ts
+++ b/x-pack/test_serverless/functional/page_objects/index.ts
@@ -21,6 +21,7 @@ import { SvlRuleDetailsPageProvider } from './svl_rule_details_ui_page';
import { SvlSearchConnectorsPageProvider } from './svl_search_connectors_page';
import { SvlManagementPageProvider } from './svl_management_page';
import { SvlIngestPipelines } from './svl_ingest_pipelines';
+import { SvlSearchHomePageProvider } from './svl_search_homepage';
export const pageObjects = {
...xpackFunctionalPageObjects,
@@ -38,4 +39,5 @@ export const pageObjects = {
svlRuleDetailsUI: SvlRuleDetailsPageProvider,
svlManagementPage: SvlManagementPageProvider,
svlIngestPipelines: SvlIngestPipelines,
+ svlSearchHomePage: SvlSearchHomePageProvider,
};
diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts b/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts
new file mode 100644
index 0000000000000..eeb1b6de731f9
--- /dev/null
+++ b/x-pack/test_serverless/functional/page_objects/svl_search_homepage.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../ftr_provider_context';
+
+export function SvlSearchHomePageProvider({ getService }: FtrProviderContext) {
+ const testSubjects = getService('testSubjects');
+ const browser = getService('browser');
+
+ return {
+ async expectToBeOnHomepage() {
+ expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/home');
+ },
+ async expectToNotBeOnHomepage() {
+ expect(await browser.getCurrentUrl()).not.contain('/app/elasticsearch/home');
+ },
+ async expectHomepageHeader() {
+ await testSubjects.existOrFail('search-homepage-header', { timeout: 2000 });
+ },
+ };
+}
diff --git a/x-pack/test_serverless/functional/services/index.ts b/x-pack/test_serverless/functional/services/index.ts
index a1112232377cd..c63a16b4402f1 100644
--- a/x-pack/test_serverless/functional/services/index.ts
+++ b/x-pack/test_serverless/functional/services/index.ts
@@ -16,6 +16,7 @@ import { SvlCommonScreenshotsProvider } from './svl_common_screenshots';
import { SvlCasesServiceProvider } from '../../api_integration/services/svl_cases';
import { MachineLearningProvider } from './ml';
import { LogsSynthtraceProvider } from './log';
+import { UISettingsServiceProvider } from './ui_settings';
export const services = {
// deployment agnostic FTR services
@@ -30,6 +31,7 @@ export const services = {
svlCommonScreenshots: SvlCommonScreenshotsProvider,
svlCases: SvlCasesServiceProvider,
svlMl: MachineLearningProvider,
+ uiSettings: UISettingsServiceProvider,
// log services
svlLogsSynthtraceClient: LogsSynthtraceProvider,
};
diff --git a/x-pack/test_serverless/functional/services/ui_settings.ts b/x-pack/test_serverless/functional/services/ui_settings.ts
new file mode 100644
index 0000000000000..337930790489d
--- /dev/null
+++ b/x-pack/test_serverless/functional/services/ui_settings.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../ftr_provider_context';
+import { RoleCredentials } from '../../shared/services';
+
+export function UISettingsServiceProvider({ getService }: FtrProviderContext) {
+ const svlCommonApi = getService('svlCommonApi');
+ const supertestWithoutAuth = getService('supertestWithoutAuth');
+
+ return {
+ async setUiSetting(role: RoleCredentials, settingId: string, value: unknown) {
+ await supertestWithoutAuth
+ .post(`/internal/kibana/settings/${settingId}`)
+ .set(svlCommonApi.getInternalRequestHeader())
+ .set(role.apiKeyHeader)
+ .send({ value })
+ .expect(200);
+ },
+ async deleteUISetting(role: RoleCredentials, settingId: string) {
+ await supertestWithoutAuth
+ .delete(`/internal/kibana/settings/${settingId}`)
+ .set(svlCommonApi.getInternalRequestHeader())
+ .set(role.apiKeyHeader)
+ .expect(200);
+ },
+ };
+}
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 455acc0404429..8c3cfd83e04e9 100644
--- a/x-pack/test_serverless/functional/test_suites/search/index.ts
+++ b/x-pack/test_serverless/functional/test_suites/search/index.ts
@@ -23,5 +23,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./playground_overview'));
loadTestFile(require.resolve('./ml'));
+ loadTestFile(require.resolve('./search_homepage'));
});
}
diff --git a/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts
new file mode 100644
index 0000000000000..3138e0e7f0242
--- /dev/null
+++ b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts
@@ -0,0 +1,58 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../../ftr_provider_context';
+import { RoleCredentials } from '../../../shared/services';
+
+import { testHasEmbeddedConsole } from './embedded_console';
+
+export default function ({ getPageObjects, getService }: FtrProviderContext) {
+ const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'svlSearchHomePage']);
+ const svlUserManager = getService('svlUserManager');
+ const uiSettings = getService('uiSettings');
+ let roleAuthc: RoleCredentials;
+
+ const HOMEPAGE_FF_UI_SETTING = 'searchHomepage:homepageEnabled';
+ describe('Search Homepage', function () {
+ this.tags('skipMKI');
+ before(async () => {
+ roleAuthc = await svlUserManager.createApiKeyForRole('admin');
+ // Enable Homepage Feature Flag
+ await uiSettings.setUiSetting(roleAuthc, HOMEPAGE_FF_UI_SETTING, true);
+
+ await pageObjects.svlCommonPage.login();
+ });
+
+ after(async () => {
+ if (!roleAuthc) return;
+
+ // Disable Homepage Feature Flag
+ await uiSettings.deleteUISetting(roleAuthc, HOMEPAGE_FF_UI_SETTING);
+
+ await pageObjects.svlCommonPage.forceLogout();
+ });
+
+ it('has search homepage with Home sidenav', async () => {
+ pageObjects.svlSearchHomePage.expectToBeOnHomepage();
+ pageObjects.svlSearchHomePage.expectHomepageHeader();
+ // Navigate to another page
+ await pageObjects.svlCommonNavigation.sidenav.clickLink({
+ deepLinkId: 'serverlessConnectors',
+ });
+ pageObjects.svlSearchHomePage.expectToNotBeOnHomepage();
+ // Click Home in Side nav
+ await pageObjects.svlCommonNavigation.sidenav.clickLink({
+ deepLinkId: 'searchHomepage',
+ });
+ pageObjects.svlSearchHomePage.expectToBeOnHomepage();
+ });
+
+ it('has embedded dev console', async () => {
+ testHasEmbeddedConsole(pageObjects);
+ });
+ });
+}
diff --git a/yarn.lock b/yarn.lock
index 64ba753c57695..d1dec3cae024a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6056,6 +6056,10 @@
version "0.0.0"
uid ""
+"@kbn/search-homepage@link:x-pack/plugins/search_homepage":
+ version "0.0.0"
+ uid ""
+
"@kbn/search-index-documents@link:packages/kbn-search-index-documents":
version "0.0.0"
uid ""