From 68796f12058893329a305328d59c0232ebfa3007 Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Fri, 18 Oct 2024 11:39:21 -0500 Subject: [PATCH] [Search][Serverless] Enabled Onboarding without Feature Flag (#196755) ## Summary This PR removes the feature flag check for the new search onboarding experience in Serverless. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed (cherry picked from commit e955cb044fcad83fd9e1c6631eddd95aa7357ad7) # Conflicts: # x-pack/plugins/serverless_search/public/navigation_tree.ts # x-pack/test_serverless/functional/test_suites/search/index.ts # x-pack/test_serverless/functional/test_suites/search/navigation.ts --- x-pack/plugins/search_indices/common/index.ts | 2 - .../search_indices/public/feature_flags.ts | 13 -- .../plugins/search_indices/public/plugin.ts | 8 - x-pack/plugins/serverless_search/kibana.jsonc | 2 +- .../public/navigation_tree.ts | 57 +++-- .../serverless_search/public/plugin.ts | 53 ++--- .../plugins/serverless_search/public/types.ts | 4 +- .../services/svl_search_navigation.ts | 3 +- .../search/config.feature_flags.ts | 7 +- .../functional/test_suites/search/config.ts | 8 +- .../test_suites/search/console_notebooks.ts | 5 +- .../test_suites/search/index.feature_flags.ts | 4 +- .../functional/test_suites/search/index.ts | 4 +- .../test_suites/search/navigation.ts | 209 +++++++++++++++++- 14 files changed, 282 insertions(+), 97 deletions(-) delete mode 100644 x-pack/plugins/search_indices/public/feature_flags.ts diff --git a/x-pack/plugins/search_indices/common/index.ts b/x-pack/plugins/search_indices/common/index.ts index 3b8ffc50812611..e640397e3936d8 100644 --- a/x-pack/plugins/search_indices/common/index.ts +++ b/x-pack/plugins/search_indices/common/index.ts @@ -12,6 +12,4 @@ export const PLUGIN_NAME = 'searchIndices'; export const START_APP_ID: SearchStart = 'elasticsearchStart'; export const INDICES_APP_ID: SearchIndices = 'elasticsearchIndices'; -export const GLOBAL_EMPTY_STATE_FEATURE_FLAG_ID = 'searchIndices:globalEmptyStateEnabled'; - export type { IndicesStatusResponse, UserStartPrivilegesResponse } from './types'; diff --git a/x-pack/plugins/search_indices/public/feature_flags.ts b/x-pack/plugins/search_indices/public/feature_flags.ts deleted file mode 100644 index ec114506d4f8cc..00000000000000 --- a/x-pack/plugins/search_indices/public/feature_flags.ts +++ /dev/null @@ -1,13 +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 { IUiSettingsClient } from '@kbn/core/public'; -import { GLOBAL_EMPTY_STATE_FEATURE_FLAG_ID } from '../common'; - -export function isGlobalEmptyStateEnabled(uiSettings: IUiSettingsClient): boolean { - return uiSettings.get(GLOBAL_EMPTY_STATE_FEATURE_FLAG_ID, false); -} diff --git a/x-pack/plugins/search_indices/public/plugin.ts b/x-pack/plugins/search_indices/public/plugin.ts index 8ff86d4d3c7747..2f9a8ca3cf950d 100644 --- a/x-pack/plugins/search_indices/public/plugin.ts +++ b/x-pack/plugins/search_indices/public/plugin.ts @@ -18,7 +18,6 @@ import type { import { initQueryClient } from './services/query_client'; import { INDICES_APP_ID, START_APP_ID } from '../common'; import { INDICES_APP_BASE, START_APP_BASE } from './routes'; -import { isGlobalEmptyStateEnabled } from './feature_flags'; export class SearchIndicesPlugin implements Plugin @@ -28,13 +27,6 @@ export class SearchIndicesPlugin public setup( core: CoreSetup ): SearchIndicesPluginSetup { - if (!isGlobalEmptyStateEnabled(core.uiSettings)) { - return { - enabled: this.pluginEnabled, - startAppId: START_APP_ID, - startRoute: START_APP_BASE, - }; - } this.pluginEnabled = true; const queryClient = initQueryClient(core.notifications.toasts); diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 8ef675723cf0e9..504c346262492a 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -16,6 +16,7 @@ "devTools", "discover", "management", + "searchIndices", "searchprofiler", "security", "serverless", @@ -25,7 +26,6 @@ "optionalPlugins": [ "indexManagement", "searchConnectors", - "searchIndices", "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 1b3b980ec9fa5b..1a059670fe9270 100644 --- a/x-pack/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_search/public/navigation_tree.ts @@ -5,27 +5,11 @@ * 2.0. */ -import type { - AppDeepLinkId, - NavigationTreeDefinition, - NodeDefinition, -} from '@kbn/core-chrome-browser'; +import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; import { i18n } from '@kbn/i18n'; import { CONNECTORS_LABEL } from '../common/i18n_string'; -const gettingStartedItem: NodeDefinition = { - id: 'gettingStarted', - title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', { - defaultMessage: 'Getting Started', - }), - link: 'serverlessElasticsearch', - spaceBefore: 'm', -}; - -export const navigationTree = ( - homeLink: AppDeepLinkId = 'serverlessElasticsearch' as AppDeepLinkId, - showGettingStarted: boolean -): NavigationTreeDefinition => ({ +export const navigationTree = (): NavigationTreeDefinition => ({ body: [ { type: 'navGroup', @@ -41,7 +25,7 @@ export const navigationTree = ( title: i18n.translate('xpack.serverlessSearch.nav.home', { defaultMessage: 'Home', }), - link: homeLink, + link: 'elasticsearchStart', spaceBefore: 'm', }, { @@ -138,7 +122,40 @@ export const navigationTree = ( }, ], }, - ...(showGettingStarted ? [gettingStartedItem] : []), + { + id: 'analyze', + title: i18n.translate('xpack.serverlessSearch.nav.analyze', { + defaultMessage: 'Analyze', + }), + spaceBefore: 'm', + children: [ + { + link: 'discover', + }, + { + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); + }, + }, + ], + }, + { + id: 'otherTools', + title: i18n.translate('xpack.serverlessSearch.nav.otherTools', { + defaultMessage: 'Other tools', + }), + spaceBefore: 'm', + children: [{ link: 'maps' }], + }, + { + id: 'gettingStarted', + title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', { + defaultMessage: 'Getting Started', + }), + link: 'serverlessElasticsearch', + spaceBefore: 'm', + }, ], }, ], diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index c223b9a6b11dbc..491252a6d9e9f2 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -73,10 +73,6 @@ export class ServerlessSearchPlugin const homeTitle = i18n.translate('xpack.serverlessSearch.app.home.title', { defaultMessage: 'Home', }); - const useGlobalEmptyState = setupDeps.searchIndices?.enabled ?? false; - const serverlessElasticsearchAppRoute = useGlobalEmptyState - ? '/app/elasticsearch/getting_started' - : '/app/elasticsearch'; core.application.register({ id: 'serverlessElasticsearch', @@ -85,7 +81,7 @@ export class ServerlessSearchPlugin }), euiIconType: 'logoElastic', category: DEFAULT_APP_CATEGORIES.enterpriseSearch, - appRoute: serverlessElasticsearchAppRoute, + appRoute: '/app/elasticsearch/getting_started', async mount({ element, history }: AppMountParameters) { const { renderApp } = await import('./application/elasticsearch'); const [coreStart, services] = await core.getStartServices(); @@ -124,23 +120,21 @@ export class ServerlessSearchPlugin }, }); - if (useGlobalEmptyState) { - const redirectApp = setupDeps.searchIndices!.startAppId; - core.application.register({ - id: 'serverlessHomeRedirect', - title: homeTitle, - appRoute: '/app/elasticsearch', - euiIconType: 'logoElastic', - category: DEFAULT_APP_CATEGORIES.enterpriseSearch, - visibleIn: [], - async mount({}: AppMountParameters) { - const [coreStart] = await core.getStartServices(); - coreStart.chrome.docTitle.change(homeTitle); - coreStart.application.navigateToApp(redirectApp); - return () => {}; - }, - }); - } + const { searchIndices } = setupDeps; + core.application.register({ + id: 'serverlessHomeRedirect', + title: homeTitle, + appRoute: '/app/elasticsearch', + euiIconType: 'logoElastic', + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + visibleIn: [], + async mount({}: AppMountParameters) { + const [coreStart] = await core.getStartServices(); + coreStart.chrome.docTitle.change(homeTitle); + coreStart.application.navigateToApp(searchIndices.startAppId); + return () => {}; + }, + }); setupDeps.discover.showInlineTopNav(); @@ -152,18 +146,9 @@ export class ServerlessSearchPlugin services: ServerlessSearchPluginStartDependencies ): ServerlessSearchPluginStart { const { serverless, management, indexManagement, security } = services; - const useGlobalEmptyState = services.searchIndices?.enabled ?? false; - const homeRoute = useGlobalEmptyState - ? services.searchIndices!.startRoute - : '/app/elasticsearch'; - serverless.setProjectHome(homeRoute); - - const navigationTree$ = of( - navigationTree( - useGlobalEmptyState ? services.searchIndices?.startAppId : undefined, - useGlobalEmptyState - ) - ); + serverless.setProjectHome(services.searchIndices.startRoute); + + const navigationTree$ = of(navigationTree()); 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 65952c963a2a45..19b3f0fa6baa59 100644 --- a/x-pack/plugins/serverless_search/public/types.ts +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -31,7 +31,7 @@ export interface ServerlessSearchPluginSetupDependencies { management: ManagementSetup; serverless: ServerlessPluginSetup; discover: DiscoverSetup; - searchIndices?: SearchIndicesPluginSetup; + searchIndices: SearchIndicesPluginSetup; } export interface ServerlessSearchPluginStartDependencies { @@ -44,5 +44,5 @@ export interface ServerlessSearchPluginStartDependencies { serverless: ServerlessPluginStart; share: SharePluginStart; indexManagement?: IndexManagementPluginStart; - searchIndices?: SearchIndicesPluginStart; + searchIndices: SearchIndicesPluginStart; } diff --git a/x-pack/test_serverless/functional/services/svl_search_navigation.ts b/x-pack/test_serverless/functional/services/svl_search_navigation.ts index cf91aac1127738..1f27cf18ec8cba 100644 --- a/x-pack/test_serverless/functional/services/svl_search_navigation.ts +++ b/x-pack/test_serverless/functional/services/svl_search_navigation.ts @@ -19,7 +19,8 @@ export function SvlSearchNavigationServiceProvider({ async navigateToLandingPage() { await retry.tryForTime(60 * 1000, async () => { await PageObjects.common.navigateToApp('landingPage'); - await testSubjects.existOrFail('svlSearchOverviewPage', { timeout: 2000 }); + // Wait for the side nav, since the landing page will sometimes redirect to index management now + await testSubjects.existOrFail('svlSearchSideNav', { timeout: 2000 }); }); }, async navigateToGettingStartedPage() { diff --git a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts index 85724f48d38ccc..592da3d368c0de 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts @@ -26,7 +26,6 @@ export default createTestConfig({ `--xpack.cloud.organization_url=/account/members`, `--xpack.security.roleManagementEnabled=true`, `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities - `--uiSettings.overrides.searchIndices:globalEmptyStateEnabled=true`, // global empty state FF ], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], @@ -38,6 +37,12 @@ export default createTestConfig({ serverlessElasticsearch: { pathname: '/app/elasticsearch/getting_started', }, + serverlessConnectors: { + pathname: '/app/connectors', + }, + searchPlayground: { + pathname: '/app/search_playground', + }, elasticsearchStart: { pathname: '/app/elasticsearch/start', }, diff --git a/x-pack/test_serverless/functional/test_suites/search/config.ts b/x-pack/test_serverless/functional/test_suites/search/config.ts index 678adecd4bff56..35f6ca23f7cc85 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.ts @@ -26,7 +26,7 @@ export default createTestConfig({ ], apps: { serverlessElasticsearch: { - pathname: '/app/elasticsearch', + pathname: '/app/elasticsearch/getting_started', }, serverlessConnectors: { pathname: '/app/connectors', @@ -34,5 +34,11 @@ export default createTestConfig({ searchPlayground: { pathname: '/app/search_playground', }, + elasticsearchStart: { + pathname: '/app/elasticsearch/start', + }, + elasticsearchIndices: { + pathname: '/app/elasticsearch/indices', + }, }, }); diff --git a/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts b/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts index 5cf4a4ceeb856b..8d1377bce93a3b 100644 --- a/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts +++ b/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts @@ -7,12 +7,15 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getPageObjects }: FtrProviderContext) { +export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['svlCommonPage', 'embeddedConsole']); + const svlSearchNavigation = getService('svlSearchNavigation'); describe('Console Notebooks', function () { before(async () => { await pageObjects.svlCommonPage.loginAsViewer(); + + await svlSearchNavigation.navigateToGettingStartedPage(); }); it('has notebooks view available', async () => { diff --git a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts index db9df2e8d913cb..bc9e19f2ae71fb 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts @@ -10,9 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI - feature flags', function () { // add tests that require feature flags, defined in config.feature_flags.ts - loadTestFile(require.resolve('./elasticsearch_start.ts')); - loadTestFile(require.resolve('./search_index_detail.ts')); - loadTestFile(require.resolve('./getting_started')); + loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); loadTestFile(require.resolve('../common/platform_security/roles.ts')); loadTestFile(require.resolve('../common/spaces/multiple_spaces_enabled.ts')); 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 b2be587e51ea51..903f98c63b776a 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -11,10 +11,12 @@ export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI', function () { this.tags(['esGate']); + loadTestFile(require.resolve('./navigation')); + loadTestFile(require.resolve('./elasticsearch_start.ts')); + loadTestFile(require.resolve('./search_index_detail.ts')); loadTestFile(require.resolve('./getting_started')); loadTestFile(require.resolve('./connectors/connectors_overview')); loadTestFile(require.resolve('./default_dataview')); - loadTestFile(require.resolve('./navigation')); loadTestFile(require.resolve('./pipelines')); loadTestFile(require.resolve('./cases/attachment_framework')); loadTestFile(require.resolve('./dashboards/build_dashboard')); diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 9476010f58f548..ec41ebf7ec92d2 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -13,6 +13,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { const svlSearchNavigation = getService('svlSearchNavigation'); const svlCommonNavigation = getPageObject('svlCommonNavigation'); const svlCommonPage = getPageObject('svlCommonPage'); + const solutionNavigation = getPageObject('solutionNavigation'); const testSubjects = getService('testSubjects'); const browser = getService('browser'); const header = getPageObject('header'); @@ -31,13 +32,14 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlSearchLandingPage.assertSvlSearchSideNavExists(); // check side nav links - await testSubjects.existOrFail(`svlSearchOverviewPage`); - await svlCommonNavigation.sidenav.expectLinkActive({ - deepLinkId: 'serverlessElasticsearch', + await solutionNavigation.sidenav.expectSectionExists('search_project_nav'); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'elasticsearchStart', }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'serverlessElasticsearch', + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'elasticsearchStart', }); + await testSubjects.existOrFail(`elasticsearchStartPage`); // TODO: test something search project specific instead of generic discover // navigate to discover @@ -51,16 +53,153 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'management:index_management', }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: `Index Management` }); - await testSubjects.existOrFail(`indicesTab`); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'management:index_management', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Data' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Index Management' }); + + // > Connectors + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'serverlessConnectors', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'serverlessConnectors', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Data' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Connectors' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'serverlessConnectors', + }); + // check Build + // > Dev Tools + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'dev_tools', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'dev_tools', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Build' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Dev Tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'dev_tools', + }); + // > Playground + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'searchPlayground', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'searchPlayground', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Build' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Playground' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'searchPlayground', + }); + // check Relevance + // > Inference Endpoints + // await solutionNavigation.sidenav.clickLink({ + // deepLinkId: 'searchInferenceEndpoints', + // }); + // await solutionNavigation.sidenav.expectLinkActive({ + // deepLinkId: 'searchInferenceEndpoints', + // }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Inference Endpoints' }); + // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + // deepLinkId: 'searchInferenceEndpoints', + // }); + + // check Analyze + // > Discover + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'discover', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'discover', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Analyze' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Discover' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'discover', + }); + // > Dashboards + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'dashboards', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'dashboards', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Analyze' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Dashboards' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'dashboards', + }); + // check Other tools + // > Maps + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'maps', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'maps', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Other tools' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Maps', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'maps', + }); + + // check Getting Started + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'serverlessElasticsearch', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'serverlessElasticsearch', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Getting Started' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Getting Started', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'serverlessElasticsearch', + }); + + // Open Project Settings + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + // check Project Settings + // > Trained Models + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'ml:modelManagement', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'ml:modelManagement', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Model Management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Trained Models' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'ml:modelManagement', + }); + // > Management + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'management', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'management', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'management', + }); // navigate back to serverless search overview await svlCommonNavigation.clickLogo(); await svlCommonNavigation.sidenav.expectLinkActive({ - deepLinkId: 'serverlessElasticsearch', + deepLinkId: 'elasticsearchStart', }); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: `Home` }); - await testSubjects.existOrFail(`svlSearchOverviewPage`); + await testSubjects.existOrFail(`elasticsearchStartPage`); await expectNoPageReload(); }); @@ -113,5 +252,57 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { expect(await browser.getCurrentUrl()).not.contain('/app/management/cases'); await testSubjects.missingOrFail('cases-all-title'); }); + + it('renders expected side navigation items', async () => { + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + // Verify all expected top-level links exist + await solutionNavigation.sidenav.expectLinkExists({ text: 'Home' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Data' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Index Management' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Connectors' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Build' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Dev Tools' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Playground' }); + // await solutionNavigation.sidenav.expectLinkExists({ text: 'Relevance' }); + // await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Analyze' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Discover' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Dashboards' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Other tools' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Maps' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Getting Started' }); + + await solutionNavigation.sidenav.expectLinkExists({ text: 'Trained models' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Management' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Users and roles' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Performance' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Billing and subscription' }); + + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + await solutionNavigation.sidenav.expectOnlyDefinedLinks([ + 'search_project_nav', + 'home', + 'data', + 'management:index_management', + 'serverlessConnectors', + 'build', + 'dev_tools', + 'searchPlayground', + // 'relevance', + // 'searchInferenceEndpoints', + 'analyze', + 'discover', + 'dashboards', + 'otherTools', + 'maps', + 'gettingStarted', + 'project_settings_project_nav', + 'ml:modelManagement', + 'management', + 'cloudLinkUserAndRoles', + 'cloudLinkDeployment', + 'cloudLinkBilling', + ]); + }); }); }