From b65c7f9070c1ac033417b9eedaf81514d3cbb72e Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Thu, 12 Dec 2024 20:32:53 +0000 Subject: [PATCH 01/29] WIP --- config/serverless.es.yml | 1 - config/serverless.oblt.yml | 2 + config/serverless.security.yml | 1 + packages/deeplinks/search/constants.ts | 2 + packages/deeplinks/search/index.ts | 2 + .../enterprise_search/common/constants.ts | 4 ++ x-pack/plugins/enterprise_search/kibana.jsonc | 3 +- .../add_domain/add_domain_logic.test.ts | 2 +- .../search_index/indices/indices_nav.test.tsx | 8 +-- .../enterprise_search_content/routes.ts | 6 +-- .../applications/shared/layout/base_nav.tsx | 2 +- .../enterprise_search/public/jest.config.js | 2 +- .../public/navigation_tree.ts | 28 ++++------ .../enterprise_search/public/plugin.ts | 4 +- .../enterprise_search/server/plugin.ts | 4 ++ x-pack/plugins/search_indices/common/index.ts | 5 +- .../plugins/search_indices/common/routes.ts | 2 + x-pack/plugins/search_indices/kibana.jsonc | 3 +- .../create_index/create_index_page.tsx | 7 +-- .../components/indices/details_page.tsx | 15 ++++-- .../public/hooks/api/use_document_search.ts | 2 +- x-pack/plugins/search_indices/public/types.ts | 2 + .../plugins/search_indices/server/config.ts | 2 +- .../search_indices/server/routes/indices.ts | 52 ++++++++++++++++++- .../setup_page/create_index_button.tsx | 26 ++++++---- 25 files changed, 134 insertions(+), 53 deletions(-) diff --git a/config/serverless.es.yml b/config/serverless.es.yml index 2d5ba84ece795..b8e12054ddf28 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -72,7 +72,6 @@ xpack.cloud.serverless.project_type: search ## Enable the Serverless Search plugin xpack.serverless.search.enabled: true -xpack.searchIndices.enabled: true ## Set the home route uiSettings.overrides.defaultRoute: /app/elasticsearch diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index 937954a1c5e84..a08f9a72e9e7b 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -9,6 +9,8 @@ xpack.securitySolution.enabled: false xpack.search.notebooks.enabled: false xpack.searchPlayground.enabled: false xpack.searchInferenceEndpoints.enabled: false +xpack.searchIndices.enabled: false + ## Fine-tune the observability solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides. xpack.features.overrides: diff --git a/config/serverless.security.yml b/config/serverless.security.yml index b9190df608540..8e2b49f782470 100644 --- a/config/serverless.security.yml +++ b/config/serverless.security.yml @@ -10,6 +10,7 @@ xpack.observabilityAIAssistant.enabled: false xpack.search.notebooks.enabled: false xpack.searchPlayground.enabled: false xpack.searchInferenceEndpoints.enabled: false +xpack.searchIndices.enabled: false ## Fine-tune the security solution feature privileges. Also, refer to `serverless.yml` for the project-agnostic overrides. xpack.features.overrides: diff --git a/packages/deeplinks/search/constants.ts b/packages/deeplinks/search/constants.ts index cd632c5b24a03..8b2a8331a5d9f 100644 --- a/packages/deeplinks/search/constants.ts +++ b/packages/deeplinks/search/constants.ts @@ -13,6 +13,8 @@ export const ENTERPRISE_SEARCH_APPLICATIONS_APP_ID = 'enterpriseSearchApplicatio export const ENTERPRISE_SEARCH_ANALYTICS_APP_ID = 'enterpriseSearchAnalytics'; export const ENTERPRISE_SEARCH_APPSEARCH_APP_ID = 'appSearch'; export const ENTERPRISE_SEARCH_WORKPLACESEARCH_APP_ID = 'workplaceSearch'; +export const SEARCH_INDICES_START_APP_ID = 'elasticsearchStart'; +export const SEARCH_INDICES_INDICES_APP_ID = 'elasticsearchIndices'; export const SERVERLESS_ES_APP_ID = 'serverlessElasticsearch'; export const SERVERLESS_ES_CONNECTORS_ID = 'serverlessConnectors'; export const SERVERLESS_ES_WEB_CRAWLERS_ID = 'serverlessWebCrawlers'; diff --git a/packages/deeplinks/search/index.ts b/packages/deeplinks/search/index.ts index 2b3d392971a5f..608a2b5165e93 100644 --- a/packages/deeplinks/search/index.ts +++ b/packages/deeplinks/search/index.ts @@ -21,6 +21,8 @@ export { SEARCH_SEMANTIC_SEARCH, SEARCH_AI_SEARCH, ES_SEARCH_PLAYGROUND_ID, + SEARCH_INDICES_START_APP_ID, + SEARCH_INDICES_INDICES_APP_ID, } from './constants'; export type { diff --git a/x-pack/plugins/enterprise_search/common/constants.ts b/x-pack/plugins/enterprise_search/common/constants.ts index 13afad3f1a342..f0765503f9916 100644 --- a/x-pack/plugins/enterprise_search/common/constants.ts +++ b/x-pack/plugins/enterprise_search/common/constants.ts @@ -18,6 +18,8 @@ import { SEARCH_VECTOR_SEARCH, SEARCH_SEMANTIC_SEARCH, SEARCH_AI_SEARCH, + SEARCH_INDICES_INDICES_APP_ID, + SEARCH_INDICES_START_APP_ID, } from '@kbn/deeplinks-search'; import { i18n } from '@kbn/i18n'; @@ -32,6 +34,8 @@ export const ENTERPRISE_SEARCH_PRODUCT_NAME = i18n.translate('xpack.enterpriseSe defaultMessage: 'Enterprise Search', }); +export { SEARCH_INDICES_START_APP_ID, SEARCH_INDICES_INDICES_APP_ID }; + export const ENTERPRISE_SEARCH_OVERVIEW_PLUGIN = { ID: ENTERPRISE_SEARCH_APP_ID, NAME: SEARCH_PRODUCT_NAME, diff --git a/x-pack/plugins/enterprise_search/kibana.jsonc b/x-pack/plugins/enterprise_search/kibana.jsonc index 42e4db528a759..c959e335cd734 100644 --- a/x-pack/plugins/enterprise_search/kibana.jsonc +++ b/x-pack/plugins/enterprise_search/kibana.jsonc @@ -41,7 +41,8 @@ "charts", "cloud", "lens", - "share" + "share", + "search_indices" ], "requiredBundles": ["kibanaReact"] } diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts index 83101c4b90fd6..9d20e50020015 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts @@ -309,7 +309,7 @@ describe('AddDomainLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); expect(navigateToUrl).toHaveBeenCalledWith( - '/search_indices/index-name/domain_management/test-domain' + '/app/management/data/index_management/indices/index-name/domain_management/test-domain' ); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx index d7ac65e07f284..aeed49eca0fe0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx @@ -44,24 +44,24 @@ describe('useIndicesNav', () => { id: 'indexName', name: 'INDEX-NAME', 'data-test-subj': 'IndexLabel', - href: '/search_indices/index-name', + href: '/app/management/data/index_management/indices/index-name', items: [ { id: 'overview', name: 'Overview', - href: '/search_indices/index-name/overview', + href: '/app/management/data/index_management/indices/index-name/overview', 'data-test-subj': 'IndexOverviewLink', }, { id: 'documents', name: 'Documents', - href: '/search_indices/index-name/documents', + href: '/app/management/data/index_management/indices/index-name/documents', 'data-test-subj': 'IndexDocumentsLink', }, { id: 'index_mappings', name: 'Index mappings', - href: '/search_indices/index-name/index_mappings', + href: '/app/management/data/index_management/indices/index-name/index_mappings', 'data-test-subj': 'IndexIndexMappingsLink', }, ], diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts index 092b60bf7666f..a2985357c8abd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts @@ -10,12 +10,12 @@ export const ROOT_PATH = '/'; export const SETUP_GUIDE_PATH = '/setup_guide'; export const ERROR_STATE_PATH = '/error_state'; -export const SEARCH_INDICES_PATH = `${ROOT_PATH}search_indices`; +export const INDEX_MANAGEMENT_INDICES_PATH = `/app/management/data/index_management/indices`; export const CONNECTORS_PATH = `${ROOT_PATH}connectors`; export const CRAWLERS_PATH = `${ROOT_PATH}crawlers`; export const SETTINGS_PATH = `${ROOT_PATH}settings`; -export const NEW_INDEX_PATH = `${SEARCH_INDICES_PATH}/new_index`; +export const NEW_INDEX_PATH = `${INDEX_MANAGEMENT_INDICES_PATH}/new_index`; export const NEW_API_PATH = `${NEW_INDEX_PATH}/api`; export const NEW_ES_INDEX_PATH = `${NEW_INDEX_PATH}/elasticsearch`; export const NEW_DIRECT_UPLOAD_PATH = `${NEW_INDEX_PATH}/upload`; @@ -26,7 +26,7 @@ export const NEW_CRAWLER_PATH = `${CRAWLERS_PATH}/new_crawler`; export const NEW_INDEX_SELECT_CONNECTOR_NATIVE_PATH = `${CONNECTORS_PATH}/select_connector?filter=native`; export const NEW_INDEX_SELECT_CONNECTOR_CLIENTS_PATH = `${CONNECTORS_PATH}/select_connector?filter=connector_clients`; -export const SEARCH_INDEX_PATH = `${SEARCH_INDICES_PATH}/:indexName`; +export const SEARCH_INDEX_PATH = `${INDEX_MANAGEMENT_INDICES_PATH}/:indexName`; export const SEARCH_INDEX_TAB_PATH = `${SEARCH_INDEX_PATH}/:tabId`; export const SEARCH_INDEX_TAB_DETAIL_PATH = `${SEARCH_INDEX_TAB_PATH}/:detailId`; export const SEARCH_INDEX_CRAWLER_DOMAIN_DETAIL_PATH = `${SEARCH_INDEX_TAB_PATH}/:domainId`; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx index 0c1e959f7b507..0672684253889 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/base_nav.tsx @@ -53,7 +53,7 @@ export const buildBaseClassicNavItems = ({ { 'data-test-subj': 'searchSideNav-Indices', deepLink: { - link: 'enterpriseSearchContent:searchIndices', + link: 'management:index_management', shouldShowActiveForSubroutes: true, }, id: 'search_indices', diff --git a/x-pack/plugins/enterprise_search/public/jest.config.js b/x-pack/plugins/enterprise_search/public/jest.config.js index fec5a831f2fee..bcb842bf3ce7a 100644 --- a/x-pack/plugins/enterprise_search/public/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/jest.config.js @@ -10,7 +10,7 @@ module.exports = { rootDir: '../../../..', /** all nested directories have their own Jest config file */ testMatch: [ - '/x-pack/plugins/enterprise_search/public/applications/*.test.{js,mjs,ts,tsx}', + '/x-pack/plugins/enterprise_search/public/applications/**/*.test.{js,mjs,ts,tsx}', ], roots: ['/x-pack/plugins/enterprise_search/public'], collectCoverage: true, diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts index dfd639a075520..59cee65bfbbc3 100644 --- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -118,27 +118,21 @@ export const getNavigationTreeDefinition = ({ { children: [ { + title: i18n.translate('xpack.enterpriseSearch.searchNav.kibana.indices', { + defaultMessage: 'Indices', + }), + link: 'management:index_management', + breadcrumbStatus: + 'hidden' /* management sub-pages set their breadcrumbs themselves */, getIsActive: ({ pathNameSerialized, prepend }) => { - const someSubItemSelected = indices?.some((index) => - index.items?.some((item) => item.isSelected) - ); - - if (someSubItemSelected) return false; - return ( - pathNameSerialized === - prepend(`/app/enterprise_search/content${SEARCH_INDICES_PATH}`) + pathNameSerialized.startsWith( + prepend('/app/management/data/index_management/') + ) || + pathNameSerialized.startsWith(prepend('/app/elasticsearch/indices')) || + pathNameSerialized.startsWith(prepend('/app/elasticsearch/start')) ); }, - link: 'enterpriseSearchContent:searchIndices', - renderAs: 'item', - ...(indices - ? { - children: indices.map(euiItemTypeToNodeDefinition), - isCollapsible: false, - renderAs: 'accordion', - } - : {}), }, { link: 'enterpriseSearchContent:connectors' }, { link: 'enterpriseSearchContent:webCrawlers' }, diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index b483796540ad1..9dd91decce937 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -61,7 +61,7 @@ import { ENGINES_PATH } from './applications/app_search/routes'; import { SEARCH_APPLICATIONS_PATH } from './applications/applications/routes'; import { CONNECTORS_PATH, - SEARCH_INDICES_PATH, + INDEX_MANAGEMENT_INDICES_PATH, CRAWLERS_PATH, } from './applications/enterprise_search_content/routes'; @@ -118,7 +118,7 @@ const contentLinks: AppDeepLink[] = [ }, { id: 'searchIndices', - path: `/${SEARCH_INDICES_PATH}`, + path: `/app/ml/trained_models`, title: i18n.translate('xpack.enterpriseSearch.navigation.contentIndicesLinkLabel', { defaultMessage: 'Indices', }), diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index 6079e53e618e6..d69b9e45e01f0 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -47,6 +47,8 @@ import { AI_SEARCH_PLUGIN, APPLICATIONS_PLUGIN, SEARCH_PRODUCT_NAME, + SEARCH_INDICES_INDICES_APP_ID, + SEARCH_INDICES_START_APP_ID, } from '../common/constants'; import { @@ -176,6 +178,8 @@ export class EnterpriseSearchPlugin implements Plugin { SEMANTIC_SEARCH_PLUGIN.ID, APPLICATIONS_PLUGIN.ID, AI_SEARCH_PLUGIN.ID, + SEARCH_INDICES_INDICES_APP_ID, + SEARCH_INDICES_START_APP_ID, ]; const isCloud = !!cloud?.cloudId; diff --git a/x-pack/plugins/search_indices/common/index.ts b/x-pack/plugins/search_indices/common/index.ts index e640397e3936d..63f9466f29f1e 100644 --- a/x-pack/plugins/search_indices/common/index.ts +++ b/x-pack/plugins/search_indices/common/index.ts @@ -6,10 +6,11 @@ */ import type { SearchIndices, SearchStart } from '@kbn/deeplinks-search/deep_links'; +import { SEARCH_INDICES_INDICES_APP_ID, SEARCH_INDICES_START_APP_ID } from '@kbn/deeplinks-search'; export const PLUGIN_ID = 'searchIndices'; export const PLUGIN_NAME = 'searchIndices'; -export const START_APP_ID: SearchStart = 'elasticsearchStart'; -export const INDICES_APP_ID: SearchIndices = 'elasticsearchIndices'; +export const START_APP_ID: SearchStart = SEARCH_INDICES_START_APP_ID; +export const INDICES_APP_ID: SearchIndices = SEARCH_INDICES_INDICES_APP_ID; export type { IndicesStatusResponse, UserStartPrivilegesResponse } from './types'; diff --git a/x-pack/plugins/search_indices/common/routes.ts b/x-pack/plugins/search_indices/common/routes.ts index f527fa676e2a0..7db8fb1a89033 100644 --- a/x-pack/plugins/search_indices/common/routes.ts +++ b/x-pack/plugins/search_indices/common/routes.ts @@ -11,3 +11,5 @@ export const GET_USER_PRIVILEGES_ROUTE = '/internal/search_indices/start_privile export const POST_CREATE_INDEX_ROUTE = '/internal/search_indices/indices/create'; export const INDEX_DOCUMENT_ROUTE = '/internal/search_indices/{indexName}/documents/{id}'; + +export const SEARCH_DOCUMENTS_ROUTE = '/internal/search_indices/{indexName}/documents/search'; diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index 50778c3fbb4e4..68a86a01587a0 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -20,7 +20,8 @@ "cloud", "console", "usageCollection", - "serverless" + "serverless", + "searchNavigation" ], "requiredBundles": [ "kibanaReact", diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx index 56ee5f49c5339..180e5ee8786a6 100644 --- a/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx @@ -24,7 +24,7 @@ const CreateIndexLabel = i18n.translate('xpack.searchIndices.createIndex.docTitl }); export const CreateIndexPage = () => { - const { console: consolePlugin } = useKibana().services; + const { console: consolePlugin, history, searchNavigation } = useKibana().services; const { data: indicesData, isInitialLoading, @@ -39,11 +39,12 @@ export const CreateIndexPage = () => { usePageChrome(CreateIndexLabel, [...IndexManagementBreadcrumbs, { text: CreateIndexLabel }]); return ( - {isInitialLoading && } @@ -53,6 +54,6 @@ export const CreateIndexPage = () => { )} {embeddableConsole} - + ); }; diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index fb09943710dc6..e7d9eb96bb660 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -21,6 +21,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; import { ApiKeyForm } from '@kbn/search-api-keys-components'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { useNavigateToDiscover } from '../../hooks/use_navigate_to_discover'; import { useIndex } from '../../hooks/api/use_index'; import { useKibana } from '../../hooks/use_kibana'; @@ -45,7 +46,14 @@ export const SearchIndexDetailsPage = () => { const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName); const tabId = decodeURIComponent(useParams<{ tabId: string }>().tabId); - const { console: consolePlugin, docLinks, application, history, share } = useKibana().services; + const { + console: consolePlugin, + docLinks, + application, + history, + share, + searchNavigation, + } = useKibana().services; const { data: index, refetch, @@ -189,13 +197,14 @@ export const SearchIndexDetailsPage = () => { } return ( - {isIndexError || isMappingsError || !index || !mappings || !indexDocuments ? ( { /> )} {embeddableConsole} - + ); }; diff --git a/x-pack/plugins/search_indices/public/hooks/api/use_document_search.ts b/x-pack/plugins/search_indices/public/hooks/api/use_document_search.ts index d566b90916892..a8afd69385623 100644 --- a/x-pack/plugins/search_indices/public/hooks/api/use_document_search.ts +++ b/x-pack/plugins/search_indices/public/hooks/api/use_document_search.ts @@ -33,7 +33,7 @@ export const useIndexDocumentSearch = (indexName: string) => { refetchIntervalInBackground: true, refetchOnWindowFocus: 'always', queryFn: async ({ signal }) => - http.post(`/internal/serverless_search/indices/${indexName}/search`, { + http.post(`/internal/search_indices/${indexName}/documents/search`, { body: JSON.stringify({ searchQuery: '', trackTotalHits: true, diff --git a/x-pack/plugins/search_indices/public/types.ts b/x-pack/plugins/search_indices/public/types.ts index ccf4d56e13a67..105e496c179c8 100644 --- a/x-pack/plugins/search_indices/public/types.ts +++ b/x-pack/plugins/search_indices/public/types.ts @@ -44,6 +44,7 @@ export interface AppPluginSetupDependencies { share: SharePluginSetup; serverless?: ServerlessPluginSetup; usageCollection?: UsageCollectionSetup; + search; } export interface SearchIndicesAppPluginStartDependencies { @@ -53,6 +54,7 @@ export interface SearchIndicesAppPluginStartDependencies { serverless?: ServerlessPluginStart; usageCollection?: UsageCollectionStart; indexManagement: IndexManagementPluginStart; + searchNavigation?: SearchNavigationPluginStart; } export interface SearchIndicesServicesContextDeps { diff --git a/x-pack/plugins/search_indices/server/config.ts b/x-pack/plugins/search_indices/server/config.ts index 408d45cf23e2e..7aab566c6a7f0 100644 --- a/x-pack/plugins/search_indices/server/config.ts +++ b/x-pack/plugins/search_indices/server/config.ts @@ -9,7 +9,7 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { PluginConfigDescriptor } from '@kbn/core/server'; const configSchema = schema.object({ - enabled: schema.boolean({ defaultValue: false }), + enabled: schema.boolean({ defaultValue: true }), }); export type SearchIndicesConfig = TypeOf; diff --git a/x-pack/plugins/search_indices/server/routes/indices.ts b/x-pack/plugins/search_indices/server/routes/indices.ts index cd42470d3c3fc..d8a65f87300cd 100644 --- a/x-pack/plugins/search_indices/server/routes/indices.ts +++ b/x-pack/plugins/search_indices/server/routes/indices.ts @@ -9,8 +9,10 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import type { IRouter } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; +import { DEFAULT_DOCS_PER_PAGE } from '@kbn/search-index-documents/types'; +import { fetchSearchResults } from '@kbn/search-index-documents/lib'; -import { POST_CREATE_INDEX_ROUTE } from '../../common/routes'; +import { POST_CREATE_INDEX_ROUTE, SEARCH_DOCUMENTS_ROUTE } from '../../common/routes'; import { CreateIndexRequest } from '../../common/types'; import { createIndex } from '../lib/indices'; @@ -62,4 +64,52 @@ export function registerIndicesRoutes(router: IRouter, logger: Logger) { } } ); + + router.post( + { + path: SEARCH_DOCUMENTS_ROUTE, + validate: { + body: schema.object({ + searchQuery: schema.string({ + defaultValue: '', + }), + trackTotalHits: schema.boolean({ defaultValue: false }), + }), + params: schema.object({ + indexName: schema.string(), + }), + query: schema.object({ + page: schema.number({ defaultValue: 0, min: 0 }), + size: schema.number({ + defaultValue: DEFAULT_DOCS_PER_PAGE, + min: 0, + }), + }), + }, + }, + async (context, request, response) => { + const client = (await context.core).elasticsearch.client.asCurrentUser; + const indexName = decodeURIComponent(request.params.indexName); + const searchQuery = request.body.searchQuery; + const { page = 0, size = DEFAULT_DOCS_PER_PAGE } = request.query; + const from = page * size; + const trackTotalHits = request.body.trackTotalHits; + + const searchResults = await fetchSearchResults( + client, + indexName, + searchQuery, + from, + size, + trackTotalHits + ); + + return response.ok({ + body: { + results: searchResults, + }, + headers: { 'content-type': 'application/json' }, + }); + } + ); } diff --git a/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.tsx b/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.tsx index 5bc9f84c833fb..8471e8ab9cea8 100644 --- a/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.tsx +++ b/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.tsx @@ -7,7 +7,7 @@ import { EuiButton, EuiCallOut } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { useKibana } from '../../hooks/use_kibana'; @@ -15,27 +15,33 @@ export const CreateIndexButton: React.FC = () => { const { services: { application, share }, } = useKibana(); + const createIndexLocator = useMemo( - () => - share.url.locators.get('CREATE_INDEX_LOCATOR_ID') ?? - share.url.locators.get('SEARCH_CREATE_INDEX'), + () => share.url.locators.get('SEARCH_CREATE_INDEX'), [share.url.locators] ); - const handleNavigateToIndex = useCallback(async () => { - const createIndexUrl = await createIndexLocator?.getUrl({}); - if (createIndexUrl) { - application?.navigateToUrl(createIndexUrl); + const createIndexLinkProps = useMemo(() => { + if (createIndexLocator) { + return { + href: createIndexLocator.getRedirectUrl({}), + onClick: async (event: React.MouseEvent) => { + event.preventDefault(); + const url = await createIndexLocator.getUrl({}); + application?.navigateToUrl(url); + }, + }; } + return null; }, [application, createIndexLocator]); - return createIndexLocator ? ( + return createIndexLocator && createIndexLinkProps ? ( Date: Fri, 13 Dec 2024 12:43:01 +0000 Subject: [PATCH 02/29] remove search_index tests --- .../search_index/indices/indices_nav.tsx | 223 ------------------ .../search_index/search_index.test.tsx | 47 ---- .../components/search_index/search_index.tsx | 8 - .../enterprise_search_content/jest.config.js | 3 + .../applications/shared/layout/nav.test.tsx | 4 - .../public/applications/shared/layout/nav.tsx | 7 +- 6 files changed, 5 insertions(+), 287 deletions(-) delete mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.tsx delete mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.tsx deleted file mode 100644 index c3e754bdd9b62..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.tsx +++ /dev/null @@ -1,223 +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 { useParams, useRouteMatch } from 'react-router-dom'; - -import { useValues } from 'kea'; - -import { EuiSideNavItemType } from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; - -import { generateEncodedPath } from '../../../../shared/encode_path_params'; -import { KibanaLogic } from '../../../../shared/kibana'; -import { generateNavLink } from '../../../../shared/layout'; -import { SEARCH_INDEX_PATH, SEARCH_INDEX_TAB_PATH } from '../../../routes'; -import { isConnectorIndex, isCrawlerIndex } from '../../../utils/indices'; -import { IndexViewLogic } from '../index_view_logic'; - -import { SearchIndexTabId } from '../search_index'; - -export const useIndicesNav = () => { - const isIndexRoute = !!useRouteMatch(SEARCH_INDEX_PATH); - const { indexName } = useParams<{ indexName: string }>(); - - const { hasFilteringFeature, index } = useValues(IndexViewLogic); - const { - productFeatures: { hasDefaultIngestPipeline }, - } = useValues(KibanaLogic); - - if (!indexName || !isIndexRoute) return undefined; - - const navItems: Array> = [ - { - 'data-test-subj': 'IndexLabel', - id: 'indexName', - name: indexName.toUpperCase(), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_PATH, { - indexName, - }), - }), - items: [ - { - 'data-test-subj': 'IndexOverviewLink', - id: 'overview', - name: i18n.translate('xpack.enterpriseSearch.nav.searchIndicesTitle.nav.overviewTitle', { - defaultMessage: 'Overview', - }), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.OVERVIEW, - }), - }), - }, - { - 'data-test-subj': 'IndexDocumentsLink', - id: 'documents', - name: i18n.translate('xpack.enterpriseSearch.nav.searchIndicesTitle.nav.documentsTitle', { - defaultMessage: 'Documents', - }), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.DOCUMENTS, - }), - }), - }, - { - 'data-test-subj': 'IndexIndexMappingsLink', - id: 'index_mappings', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.indexMappingsTitle', - { - defaultMessage: 'Index mappings', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.INDEX_MAPPINGS, - }), - }), - }, - ...(isConnectorIndex(index) - ? [ - { - 'data-test-subj': 'IndexConnectorsConfigurationLink', - id: 'connectors_configuration', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.connectorsConfigurationLabel', - { - defaultMessage: 'Configuration', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.CONFIGURATION, - }), - }), - }, - ...(hasFilteringFeature - ? [ - { - 'data-test-subj': 'IndexSyncRulesLink', - id: 'syncRules', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.syncRulesLabel', - { - defaultMessage: 'Sync rules', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.SYNC_RULES, - }), - }), - }, - ] - : []), - { - 'data-test-subj': 'IndexSchedulingLink', - id: 'scheduling', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.schedulingTitle', - { - defaultMessage: 'Scheduling', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.SCHEDULING, - }), - }), - }, - ] - : []), - ...(isCrawlerIndex(index) - ? [ - { - 'data-test-subj': 'IndexDomainManagementLink', - id: 'domain_management', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.domainManagementLabel', - { - defaultMessage: 'Manage Domains', - } - ), - ...generateNavLink({ - shouldShowActiveForSubroutes: true, - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.DOMAIN_MANAGEMENT, - }), - }), - }, - { - 'data-test-subj': 'IndexCrawlerConfigurationLink', - id: 'crawler_configuration', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerConfigurationLabel', - { - defaultMessage: 'Configuration', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.CRAWLER_CONFIGURATION, - }), - }), - }, - { - 'data-test-subj': 'IndexCrawlerSchedulingLink', - id: 'crawler_scheduling', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerSchedulingLabel', - { - defaultMessage: 'Scheduling', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.SCHEDULING, - }), - }), - }, - ] - : []), - ...(hasDefaultIngestPipeline - ? [ - { - 'data-test-subj': 'IndexPipelineLink', - id: 'pipelines', - name: i18n.translate( - 'xpack.enterpriseSearch.nav.searchIndicesTitle.nav.pipelinesLabel', - { - defaultMessage: 'Pipelines', - } - ), - ...generateNavLink({ - to: generateEncodedPath(SEARCH_INDEX_TAB_PATH, { - indexName, - tabId: SearchIndexTabId.PIPELINES, - }), - }), - }, - ] - : []), - ], - }, - ]; - - return navItems; -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx deleted file mode 100644 index e5d64f960a22b..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.test.tsx +++ /dev/null @@ -1,47 +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 '../../../__mocks__/shallow_useeffect.mock'; -import { setMockValues } from '../../../__mocks__/kea_logic'; - -import React from 'react'; - -const mockUseIndicesNav = jest.fn().mockReturnValue([]); - -jest.mock('react-router-dom', () => ({ - useParams: () => ({}), -})); - -jest.mock('./indices/indices_nav', () => ({ - useIndicesNav: (...args: any[]) => mockUseIndicesNav(...args), -})); - -import { shallow } from 'enzyme'; - -import { SearchIndex } from './search_index'; - -const mockValues = { - hasFilteringFeature: false, - updateSideNavDefinition: jest.fn(), -}; - -describe('SearchIndex', () => { - it('updates the side nav dynamic links', async () => { - const updateSideNavDefinition = jest.fn(); - - setMockValues({ ...mockValues, updateSideNavDefinition }); - - const indicesItems = [{ foo: 'bar' }]; - mockUseIndicesNav.mockReturnValueOnce(indicesItems); - - shallow(); - - expect(updateSideNavDefinition).toHaveBeenCalledWith({ - indices: indicesItems, - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx index e8876a7c56818..4068b35c89283 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx @@ -42,7 +42,6 @@ import { IndexError } from './index_error'; import { SearchIndexIndexMappings } from './index_mappings'; import { IndexNameLogic } from './index_name_logic'; import { IndexViewLogic } from './index_view_logic'; -import { useIndicesNav } from './indices/indices_nav'; import { SearchIndexOverview } from './overview'; import { SearchIndexPipelines } from './pipelines/pipelines'; @@ -82,8 +81,6 @@ export const SearchIndex: React.FC = () => { updateSideNavDefinition, } = useValues(KibanaLogic); - const indicesItems = useIndicesNav(); - useEffect(() => { const subscription = guidedOnboarding?.guidedOnboardingApi ?.isGuideStepActive$('appSearch', 'add_data') @@ -117,11 +114,6 @@ export const SearchIndex: React.FC = () => { return () => subscription?.unsubscribe(); }, [guidedOnboarding, index?.count]); - useEffect(() => { - // We update the new side nav definition with the selected indices items - updateSideNavDefinition({ indices: indicesItems }); - }, [indicesItems, updateSideNavDefinition]); - useEffect(() => { return () => { updateSideNavDefinition({ indices: undefined }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js index a55b8bbc715f4..c99850777f483 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js @@ -24,5 +24,8 @@ module.exports = { modulePathIgnorePatterns: [ '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress', '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', ], }; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index 08976a4dc68c1..7d64d0a6da1ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -9,10 +9,6 @@ jest.mock('./nav_link_helpers', () => ({ generateNavLink: jest.fn(({ to, items }) => ({ href: to, items })), })); -jest.mock('../../enterprise_search_content/components/search_index/indices/indices_nav', () => ({ - useIndicesNav: () => [], -})); - import { setMockValues, mockKibanaValues } from '../../__mocks__/kea_logic'; import { renderHook } from '@testing-library/react-hooks'; 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 8f83b6c73402e..a8db83ca41637 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 @@ -15,7 +15,6 @@ import { i18n } from '@kbn/i18n'; import { ANALYTICS_PLUGIN, APPLICATIONS_PLUGIN } from '../../../../common/constants'; import { SEARCH_APPLICATIONS_PATH, SearchApplicationViewTabs } from '../../applications/routes'; -import { useIndicesNav } from '../../enterprise_search_content/components/search_index/indices/indices_nav'; import { KibanaLogic } from '../kibana'; @@ -32,8 +31,6 @@ import { generateNavLink } from './nav_link_helpers'; export const useEnterpriseSearchNav = (alwaysReturn = false) => { const { isSidebarEnabled, productAccess, getNavLinks } = useValues(KibanaLogic); - const indicesNavItems = useIndicesNav(); - const navItems: Array> = useMemo(() => { const baseNavItems = buildBaseClassicNavItems({ productAccess }); const deepLinks = getNavLinks().reduce((links, link) => { @@ -41,8 +38,8 @@ export const useEnterpriseSearchNav = (alwaysReturn = false) => { return links; }, {} as Record); - return generateSideNavItems(baseNavItems, deepLinks, { search_indices: indicesNavItems }); - }, [productAccess, indicesNavItems]); + return generateSideNavItems(baseNavItems, deepLinks); + }, [productAccess]); if (!isSidebarEnabled && !alwaysReturn) return undefined; From 70d8617116587d995fb20f71f851094fbdc45c5c Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 13 Dec 2024 19:37:24 +0000 Subject: [PATCH 03/29] FTR tests --- x-pack/test/functional/page_objects/index.ts | 8 + .../page_objects/search_api_keys.ts | 128 +++++++ .../page_objects/search_index_detail.ts | 308 +++++++++++++++++ .../page_objects/search_navigation.ts | 63 ++++ .../functional/page_objects/search_start.ts | 114 +++++++ x-pack/test/functional_search/index.ts | 2 + .../tests/classic_navigation.ts | 17 +- .../tests/search_index_detail.ts | 313 ++++++++++++++++++ .../functional_search/tests/search_start.ts | 189 +++++++++++ 9 files changed, 1135 insertions(+), 7 deletions(-) create mode 100644 x-pack/test/functional/page_objects/search_api_keys.ts create mode 100644 x-pack/test/functional/page_objects/search_index_detail.ts create mode 100644 x-pack/test/functional/page_objects/search_navigation.ts create mode 100644 x-pack/test/functional/page_objects/search_start.ts create mode 100644 x-pack/test/functional_search/tests/search_index_detail.ts create mode 100644 x-pack/test/functional_search/tests/search_start.ts diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 0d270661a05df..0641016e9a78e 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -55,6 +55,10 @@ import { WatcherPageObject } from './watcher_page'; import { SearchProfilerPageProvider } from './search_profiler_page'; import { SearchPlaygroundPageProvider } from './search_playground_page'; import { SearchClassicNavigationProvider } from './search_classic_navigation'; +import { SearchStartProvider } from './search_start'; +import { SearchApiKeysProvider } from './search_api_keys'; +import { SearchNavigationServiceProvider } from './search_navigation'; +import { SearchIndexDetailProvider } from './search_index_detail'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -94,7 +98,11 @@ export const pageObjects = { reporting: ReportingPageObject, roleMappings: RoleMappingsPageProvider, rollup: RollupPageObject, + searchApiKeys: SearchApiKeysProvider, searchClassicNavigation: SearchClassicNavigationProvider, + searchStart: SearchStartProvider, + searchIndexDetail: SearchIndexDetailProvider, + searchNavigation: SearchNavigationServiceProvider, searchProfiler: SearchProfilerPageProvider, searchPlayground: SearchPlaygroundPageProvider, searchSessionsManagement: SearchSessionsPageProvider, diff --git a/x-pack/test/functional/page_objects/search_api_keys.ts b/x-pack/test/functional/page_objects/search_api_keys.ts new file mode 100644 index 0000000000000..0ed836b9ab3d2 --- /dev/null +++ b/x-pack/test/functional/page_objects/search_api_keys.ts @@ -0,0 +1,128 @@ +/* + * 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 { SecurityApiKey } from '@elastic/elasticsearch/lib/api/types'; +import { FtrProviderContext } from '../ftr_provider_context'; + +const APIKEY_MASK = '•'.repeat(60); + +export function SearchApiKeysProvider({ getService, getPageObjects }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const pageObjects = getPageObjects(['common', 'apiKeys']); + const retry = getService('retry'); + const es = getService('es'); + + const getAPIKeyFromSessionStorage = async () => { + const sessionStorageKey = await browser.getSessionStorageItem('searchApiKey'); + return sessionStorageKey && JSON.parse(sessionStorageKey); + }; + + return { + async clearAPIKeySessionStorage() { + await browser.clearSessionStorage(); + }, + + async expectAPIKeyExists() { + await testSubjects.existOrFail('apiKeyFormAPIKey', { timeout: 1000 }); + }, + + async expectAPIKeyAvailable() { + await testSubjects.existOrFail('apiKeyFormAPIKey'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('apiKeyFormAPIKey')).to.be(APIKEY_MASK); + }); + await testSubjects.click('showAPIKeyButton'); + let apiKey; + await retry.try(async () => { + apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.be.a('string'); + expect(apiKey.length).to.be(60); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + const sessionStorageKey = await getAPIKeyFromSessionStorage(); + expect(sessionStorageKey.encoded).to.eql(apiKey); + }, + + async expectAPIKeyNoPrivileges() { + await testSubjects.existOrFail('apiKeyFormNoUserPrivileges'); + }, + + async getAPIKeyFromSessionStorage() { + return getAPIKeyFromSessionStorage(); + }, + + async getAPIKeyFromUI() { + let apiKey = ''; + await retry.try(async () => { + apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + expect(apiKey).to.be.a('string'); + return apiKey; + }, + + async invalidateAPIKey(apiKeyId: string) { + await es.security.invalidateApiKey({ ids: [apiKeyId] }); + }, + + async createAPIKey() { + await es.security.createApiKey({ + name: 'test-api-key', + role_descriptors: {}, + }); + }, + + async expectAPIKeyCreate() { + await testSubjects.existOrFail('apiKeyFormAPIKey'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('apiKeyFormAPIKey')).to.be(APIKEY_MASK); + }); + await testSubjects.click('showAPIKeyButton'); + await retry.try(async () => { + const apiKey = await testSubjects.getVisibleText('apiKeyFormAPIKey'); + expect(apiKey).to.be.a('string'); + expect(apiKey.length).to.be(60); + expect(apiKey).to.not.be(APIKEY_MASK); + }); + }, + + async deleteAPIKeys() { + const filterInvalid = (key: SecurityApiKey) => !key.invalidated; + + const { api_keys: apiKeys } = await es.security.getApiKey(); + + const validKeys = apiKeys.filter(filterInvalid); + + if (validKeys.length === 0) { + return; + } + + await es.security.invalidateApiKey({ + ids: validKeys.map((key) => key.id), + }); + }, + + async expectCreateApiKeyAction() { + await testSubjects.existOrFail('createAPIKeyButton'); + }, + + async createApiKeyFromFlyout() { + const apiKeyName = 'Happy API Key'; + await testSubjects.click('createAPIKeyButton'); + expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Create API key'); + + await pageObjects.apiKeys.setApiKeyName(apiKeyName); + await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); + }, + + async expectAPIKeyNotAvailable() { + await testSubjects.missingOrFail('apiKeyFormAPIKey'); + }, + }; +} diff --git a/x-pack/test/functional/page_objects/search_index_detail.ts b/x-pack/test/functional/page_objects/search_index_detail.ts new file mode 100644 index 0000000000000..afde1c065677e --- /dev/null +++ b/x-pack/test/functional/page_objects/search_index_detail.ts @@ -0,0 +1,308 @@ +/* + * 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 SearchIndexDetailProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const retry = getService('retry'); + + return { + async expectIndexDetailPageHeader() { + await testSubjects.existOrFail('searchIndexDetailsHeader', { timeout: 2000 }); + }, + async expectAPIReferenceDocLinkExists() { + await testSubjects.existOrFail('ApiReferenceDoc', { timeout: 2000 }); + }, + async expectActionItemReplacedWhenHasDocs() { + await testSubjects.missingOrFail('ApiReferenceDoc', { timeout: 2000 }); + await testSubjects.existOrFail('useInPlaygroundLink', { timeout: 5000 }); + await testSubjects.existOrFail('viewInDiscoverLink', { timeout: 5000 }); + }, + async expectConnectionDetails() { + await testSubjects.existOrFail('connectionDetailsEndpoint', { timeout: 2000 }); + expect(await (await testSubjects.find('connectionDetailsEndpoint')).getVisibleText()).match( + /^https?\:\/\/.*(\:\d+)?/ + ); + }, + async expectQuickStats() { + await testSubjects.existOrFail('quickStats', { timeout: 2000 }); + const quickStatsElem = await testSubjects.find('quickStats'); + const quickStatsDocumentElem = await quickStatsElem.findByTestSubject( + 'QuickStatsDocumentCount' + ); + expect(await quickStatsDocumentElem.getVisibleText()).to.contain('Document count\n0'); + expect(await quickStatsDocumentElem.getVisibleText()).not.to.contain('Index Size\n0b'); + await quickStatsDocumentElem.click(); + expect(await quickStatsDocumentElem.getVisibleText()).to.contain('Index Size\n0b'); + }, + + async expectQuickStatsToHaveDocumentCount(count: number) { + const quickStatsElem = await testSubjects.find('quickStats'); + const quickStatsDocumentElem = await quickStatsElem.findByTestSubject( + 'QuickStatsDocumentCount' + ); + expect(await quickStatsDocumentElem.getVisibleText()).to.contain(`Document count\n${count}`); + }, + + async expectQuickStatsAIMappings() { + await testSubjects.existOrFail('quickStats', { timeout: 2000 }); + const quickStatsElem = await testSubjects.find('quickStats'); + const quickStatsAIMappingsElem = await quickStatsElem.findByTestSubject( + 'QuickStatsAIMappings' + ); + await quickStatsAIMappingsElem.click(); + await testSubjects.existOrFail('setupAISearchButton', { timeout: 2000 }); + }, + + async expectQuickStatsAIMappingsToHaveVectorFields() { + const quickStatsDocumentElem = await testSubjects.find('QuickStatsAIMappings'); + await quickStatsDocumentElem.click(); + expect(await quickStatsDocumentElem.getVisibleText()).to.contain('AI Search\n1 Field'); + await testSubjects.missingOrFail('setupAISearchButton', { timeout: 2000 }); + }, + + async expectAddDocumentCodeExamples() { + await testSubjects.existOrFail('SearchIndicesAddDocumentsCode', { timeout: 2000 }); + }, + + async expectHasIndexDocuments() { + await retry.try(async () => { + await testSubjects.existOrFail('search-index-documents-result', { timeout: 2000 }); + }); + }, + + async expectMoreOptionsActionButtonExists() { + await testSubjects.existOrFail('moreOptionsActionButton'); + }, + async clickMoreOptionsActionsButton() { + await testSubjects.click('moreOptionsActionButton'); + }, + async expectMoreOptionsOverviewMenuIsShown() { + await testSubjects.existOrFail('moreOptionsContextMenu'); + }, + async expectToNavigateToPlayground(indexName: string) { + await testSubjects.click('moreOptionsPlayground'); + expect(await browser.getCurrentUrl()).contain( + `/search_playground/chat?default-index=${indexName}` + ); + await testSubjects.existOrFail('chatPage'); + }, + async expectAPIReferenceDocLinkExistsInMoreOptions() { + await testSubjects.existOrFail('moreOptionsApiReference', { timeout: 2000 }); + }, + async expectAPIReferenceDocLinkMissingInMoreOptions() { + await testSubjects.missingOrFail('moreOptionsApiReference', { timeout: 2000 }); + }, + async expectDeleteIndexButtonToBeDisabled() { + await testSubjects.existOrFail('moreOptionsDeleteIndex'); + const deleteIndexButton = await testSubjects.isEnabled('moreOptionsDeleteIndex'); + expect(deleteIndexButton).to.be(false); + await testSubjects.moveMouseTo('moreOptionsDeleteIndex'); + await testSubjects.existOrFail('moreOptionsDeleteIndexTooltip'); + }, + async expectDeleteIndexButtonToBeEnabled() { + await testSubjects.existOrFail('moreOptionsDeleteIndex'); + const deleteIndexButton = await testSubjects.isEnabled('moreOptionsDeleteIndex'); + expect(deleteIndexButton).to.be(true); + }, + async expectDeleteIndexButtonExistsInMoreOptions() { + await testSubjects.existOrFail('moreOptionsDeleteIndex'); + }, + async clickDeleteIndexButton() { + await testSubjects.click('moreOptionsDeleteIndex'); + }, + async expectDeleteIndexModalExists() { + await testSubjects.existOrFail('deleteIndexActionModal'); + }, + async clickConfirmingDeleteIndex() { + await testSubjects.existOrFail('confirmModalConfirmButton'); + await testSubjects.click('confirmModalConfirmButton'); + }, + async expectPageLoadErrorExists() { + await retry.tryForTime(60 * 1000, async () => { + await testSubjects.existOrFail('pageLoadError'); + }); + + await testSubjects.existOrFail('loadingErrorBackToIndicesButton'); + await testSubjects.existOrFail('reloadButton'); + }, + async expectIndexNotFoundErrorExists() { + const pageLoadErrorElement = await ( + await testSubjects.find('pageLoadError') + ).findByClassName('euiTitle'); + expect(await pageLoadErrorElement.getVisibleText()).to.contain('Not Found'); + }, + async clickPageReload() { + await retry.tryForTime(60 * 1000, async () => { + await testSubjects.click('reloadButton', 2000); + }); + }, + async expectTabsExists() { + await testSubjects.existOrFail('mappingsTab', { timeout: 2000 }); + await testSubjects.existOrFail('dataTab', { timeout: 2000 }); + }, + async changeTab(tab: 'dataTab' | 'mappingsTab' | 'settingsTab') { + await testSubjects.click(tab); + }, + async expectUrlShouldChangeTo(tab: 'data' | 'mappings' | 'settings') { + expect(await browser.getCurrentUrl()).contain(`/${tab}`); + }, + async expectMappingsComponentIsVisible() { + await testSubjects.existOrFail('indexDetailsMappingsToggleViewButton', { timeout: 2000 }); + }, + async expectSettingsComponentIsVisible() { + await testSubjects.existOrFail('indexDetailsSettingsEditModeSwitch', { timeout: 2000 }); + }, + async expectEditSettingsIsDisabled() { + await testSubjects.existOrFail('indexDetailsSettingsEditModeSwitch', { timeout: 2000 }); + const isEditSettingsButtonDisabled = await testSubjects.isEnabled( + 'indexDetailsSettingsEditModeSwitch' + ); + expect(isEditSettingsButtonDisabled).to.be(false); + await testSubjects.moveMouseTo('indexDetailsSettingsEditModeSwitch'); + await testSubjects.existOrFail('indexDetailsSettingsEditModeSwitchToolTip'); + }, + async expectEditSettingsToBeEnabled() { + await testSubjects.existOrFail('indexDetailsSettingsEditModeSwitch', { timeout: 2000 }); + const isEditSettingsButtonDisabled = await testSubjects.isEnabled( + 'indexDetailsSettingsEditModeSwitch' + ); + expect(isEditSettingsButtonDisabled).to.be(true); + }, + async expectSelectedLanguage(language: string) { + await testSubjects.existOrFail('codeExampleLanguageSelect'); + expect( + (await testSubjects.getVisibleText('codeExampleLanguageSelect')).toLowerCase() + ).contain(language); + }, + async selectCodingLanguage(language: string) { + await testSubjects.existOrFail('codeExampleLanguageSelect'); + await testSubjects.click('codeExampleLanguageSelect'); + await testSubjects.existOrFail(`lang-option-${language}`); + await testSubjects.click(`lang-option-${language}`); + expect( + (await testSubjects.getVisibleText('codeExampleLanguageSelect')).toLowerCase() + ).contain(language); + }, + async codeSampleContainsValue(subject: string, value: string) { + const tstSubjId = `${subject}-code-block`; + await testSubjects.existOrFail(tstSubjId); + expect(await testSubjects.getVisibleText(tstSubjId)).contain(value); + }, + async openConsoleCodeExample() { + await testSubjects.existOrFail('tryInConsoleButton'); + await testSubjects.click('tryInConsoleButton'); + }, + + async expectAPIKeyToBeVisibleInCodeBlock(apiKey: string) { + await testSubjects.existOrFail('ingestDataCodeExample-code-block'); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + apiKey + ); + }, + + async expectHasSampleDocuments() { + await testSubjects.existOrFail('ingestDataCodeExample-code-block'); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Yellowstone National Park' + ); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Yosemite National Park' + ); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Rocky Mountain National Park' + ); + }, + + async expectSampleDocumentsWithCustomMappings() { + await browser.refresh(); + await testSubjects.existOrFail('ingestDataCodeExample-code-block'); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Example text 1' + ); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Example text 2' + ); + expect(await testSubjects.getVisibleText('ingestDataCodeExample-code-block')).to.contain( + 'Example text 3' + ); + }, + + async clickFirstDocumentDeleteAction() { + await testSubjects.existOrFail('documentMetadataButton'); + await testSubjects.click('documentMetadataButton'); + await testSubjects.existOrFail('deleteDocumentButton'); + await testSubjects.click('deleteDocumentButton'); + }, + async expectDeleteDocumentActionNotVisible() { + await testSubjects.existOrFail('documentMetadataButton'); + await testSubjects.click('documentMetadataButton'); + await testSubjects.missingOrFail('deleteDocumentButton'); + }, + async expectDeleteDocumentActionIsDisabled() { + await testSubjects.existOrFail('documentMetadataButton'); + await testSubjects.click('documentMetadataButton'); + await testSubjects.existOrFail('deleteDocumentButton'); + const isDeleteDocumentEnabled = await testSubjects.isEnabled('deleteDocumentButton'); + expect(isDeleteDocumentEnabled).to.be(false); + await testSubjects.moveMouseTo('deleteDocumentButton'); + await testSubjects.existOrFail('deleteDocumentButtonToolTip'); + }, + async expectDeleteDocumentActionToBeEnabled() { + await testSubjects.existOrFail('documentMetadataButton'); + await testSubjects.click('documentMetadataButton'); + await testSubjects.existOrFail('deleteDocumentButton'); + const isDeleteDocumentEnabled = await testSubjects.isEnabled('deleteDocumentButton'); + expect(isDeleteDocumentEnabled).to.be(true); + }, + + async openIndicesDetailFromIndexManagementIndicesListTable(indexOfRow: number) { + const indexList = await testSubjects.findAll('indexTableIndexNameLink'); + await indexList[indexOfRow].click(); + await retry.waitFor('index details page title to show up', async () => { + return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; + }); + }, + async expectSearchIndexDetailsTabsExists() { + await testSubjects.existOrFail('dataTab'); + await testSubjects.existOrFail('mappingsTab'); + await testSubjects.existOrFail('settingsTab'); + }, + + async expectBreadcrumbNavigationWithIndexName(indexName: string) { + await testSubjects.existOrFail('euiBreadcrumb'); + expect(await testSubjects.getVisibleText('breadcrumb last')).to.contain(indexName); + }, + + async clickOnIndexManagementBreadcrumb() { + const breadcrumbs = await testSubjects.findAll('breadcrumb'); + for (const breadcrumb of breadcrumbs) { + if ((await breadcrumb.getVisibleText()) === 'Index Management') { + await breadcrumb.click(); + return; + } + } + }, + + async expectAddFieldToBeDisabled() { + await testSubjects.existOrFail('indexDetailsMappingsAddField'); + const isMappingsFieldEnabled = await testSubjects.isEnabled('indexDetailsMappingsAddField'); + expect(isMappingsFieldEnabled).to.be(false); + await testSubjects.moveMouseTo('indexDetailsMappingsAddField'); + await testSubjects.existOrFail('indexDetailsMappingsAddFieldTooltip'); + }, + + async expectAddFieldToBeEnabled() { + await testSubjects.existOrFail('indexDetailsMappingsAddField'); + const isMappingsFieldEnabled = await testSubjects.isEnabled('indexDetailsMappingsAddField'); + expect(isMappingsFieldEnabled).to.be(true); + }, + }; +} diff --git a/x-pack/test/functional/page_objects/search_navigation.ts b/x-pack/test/functional/page_objects/search_navigation.ts new file mode 100644 index 0000000000000..087a5152cbe7d --- /dev/null +++ b/x-pack/test/functional/page_objects/search_navigation.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export function SearchNavigationServiceProvider({ + getService, + getPageObjects, +}: FtrProviderContext) { + const retry = getService('retry'); + const { common, indexManagement } = getPageObjects(['common', 'indexManagement']); + const testSubjects = getService('testSubjects'); + + return { + async navigateToLandingPage() { + await retry.tryForTime(60 * 1000, async () => { + await common.navigateToApp('landingPage'); + // Wait for the side nav, since the landing page will sometimes redirect to index management now + await testSubjects.existOrFail('svlSearchSideNav', { timeout: 2000 }); + }); + }, + async navigateToGettingStartedPage() { + await retry.tryForTime(60 * 1000, async () => { + await common.navigateToApp('serverlessElasticsearch'); + await testSubjects.existOrFail('svlSearchOverviewPage', { timeout: 2000 }); + }); + }, + async navigateToElasticsearchStartPage(expectRedirect: boolean = false) { + await retry.tryForTime(60 * 1000, async () => { + await common.navigateToApp('elasticsearch/start', { + shouldLoginIfPrompted: false, + }); + if (!expectRedirect) { + await testSubjects.existOrFail('elasticsearchStartPage', { timeout: 2000 }); + } + }); + }, + async navigateToIndexDetailPage(indexName: string) { + await retry.tryForTime(60 * 1000, async () => { + await common.navigateToApp(`elasticsearch/indices/index_details/${indexName}`, { + shouldLoginIfPrompted: false, + }); + }); + await testSubjects.existOrFail('searchIndicesDetailsPage', { timeout: 2000 }); + }, + async navigateToInferenceManagementPage(expectRedirect: boolean = false) { + await common.navigateToApp('searchInferenceEndpoints', { + shouldLoginIfPrompted: false, + }); + }, + + async navigateToIndexManagementPage() { + await retry.tryForTime(60 * 1000, async () => { + await common.navigateToApp('management/data/index_management'); + await indexManagement.expectToBeOnIndicesManagement(); + }); + }, + }; +} diff --git a/x-pack/test/functional/page_objects/search_start.ts b/x-pack/test/functional/page_objects/search_start.ts new file mode 100644 index 0000000000000..7d73c17a175a6 --- /dev/null +++ b/x-pack/test/functional/page_objects/search_start.ts @@ -0,0 +1,114 @@ +/* + * 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 SearchStartProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + const retry = getService('retry'); + + return { + async expectToBeOnStartPage() { + expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/start'); + await testSubjects.existOrFail('elasticsearchStartPage', { timeout: 2000 }); + }, + async expectToBeOnIndexDetailsPage() { + await retry.tryForTime(60 * 1000, async () => { + expect(await browser.getCurrentUrl()).contain('/app/elasticsearch/indices/index_details'); + }); + }, + async expectToBeOnIndexListPage() { + await retry.tryForTime(60 * 1000, async () => { + expect(await browser.getCurrentUrl()).contain( + '/app/management/data/index_management/indices' + ); + }); + }, + async expectToBeOnMLFileUploadPage() { + await retry.tryForTime(60 * 1000, async () => { + expect(await browser.getCurrentUrl()).contain('/app/ml/filedatavisualizer'); + }); + }, + async expectIndexNameToExist() { + await testSubjects.existOrFail('indexNameField'); + }, + async setIndexNameValue(value: string) { + await testSubjects.existOrFail('indexNameField'); + await testSubjects.setValue('indexNameField', value); + }, + async expectCloseCreateIndexButtonExists() { + await testSubjects.existOrFail('closeCreateIndex'); + }, + async clickCloseCreateIndexButton() { + await testSubjects.existOrFail('closeCreateIndex'); + await testSubjects.click('closeCreateIndex'); + }, + async expectSkipButtonExists() { + await testSubjects.existOrFail('createIndexSkipBtn'); + }, + async clickSkipButton() { + await testSubjects.existOrFail('createIndexSkipBtn'); + await testSubjects.click('createIndexSkipBtn'); + }, + async expectCreateIndexButtonToExist() { + await testSubjects.existOrFail('createIndexBtn'); + }, + async expectCreateIndexButtonToBeEnabled() { + await testSubjects.existOrFail('createIndexBtn'); + expect(await testSubjects.isEnabled('createIndexBtn')).equal(true); + }, + async expectCreateIndexButtonToBeDisabled() { + await testSubjects.existOrFail('createIndexBtn'); + expect(await testSubjects.isEnabled('createIndexBtn')).equal(false); + }, + async clickCreateIndexButton() { + await testSubjects.existOrFail('createIndexBtn'); + expect(await testSubjects.isEnabled('createIndexBtn')).equal(true); + await testSubjects.click('createIndexBtn'); + }, + async expectCreateIndexCodeView() { + await testSubjects.existOrFail('createIndexCodeView'); + }, + async expectCreateIndexUIView() { + await testSubjects.existOrFail('createIndexUIView'); + }, + async clickUIViewButton() { + await testSubjects.existOrFail('createIndexUIViewBtn'); + await testSubjects.click('createIndexUIViewBtn'); + }, + async clickCodeViewButton() { + await testSubjects.existOrFail('createIndexCodeViewBtn'); + await testSubjects.click('createIndexCodeViewBtn'); + }, + async clickFileUploadLink() { + await testSubjects.existOrFail('uploadFileLink'); + await testSubjects.click('uploadFileLink'); + }, + + async expectAPIKeyVisibleInCodeBlock(apiKey: string) { + await testSubjects.existOrFail('createIndex-code-block'); + await retry.try(async () => { + expect(await testSubjects.getVisibleText('createIndex-code-block')).to.contain(apiKey); + }); + }, + + async expectAPIKeyPreGenerated() { + await testSubjects.existOrFail('apiKeyHasBeenGenerated'); + }, + + async expectAPIKeyNotPreGenerated() { + await testSubjects.existOrFail('apiKeyHasNotBeenGenerated'); + }, + + async expectAPIKeyFormNotAvailable() { + await testSubjects.missingOrFail('apiKeyHasNotBeenGenerated'); + await testSubjects.missingOrFail('apiKeyHasBeenGenerated'); + }, + }; +} diff --git a/x-pack/test/functional_search/index.ts b/x-pack/test/functional_search/index.ts index d48bd1d695d16..14c87b82c825d 100644 --- a/x-pack/test/functional_search/index.ts +++ b/x-pack/test/functional_search/index.ts @@ -12,5 +12,7 @@ export default ({ loadTestFile }: FtrProviderContext): void => { describe('Search solution tests', function () { loadTestFile(require.resolve('./tests/classic_navigation')); loadTestFile(require.resolve('./tests/solution_navigation')); + loadTestFile(require.resolve('./tests/search_start')); + loadTestFile(require.resolve('./tests/search_index_detail')); }); }; diff --git a/x-pack/test/functional_search/tests/classic_navigation.ts b/x-pack/test/functional_search/tests/classic_navigation.ts index a290f7523f49c..2cc8457a42e8d 100644 --- a/x-pack/test/functional_search/tests/classic_navigation.ts +++ b/x-pack/test/functional_search/tests/classic_navigation.ts @@ -11,7 +11,11 @@ export default function searchSolutionNavigation({ getPageObjects, getService, }: FtrProviderContext) { - const { common, searchClassicNavigation } = getPageObjects(['common', 'searchClassicNavigation']); + const { common, searchClassicNavigation, indexManagement } = getPageObjects([ + 'common', + 'searchClassicNavigation', + 'indexManagement', + ]); const spaces = getService('spaces'); const browser = getService('browser'); @@ -61,12 +65,6 @@ export default function searchSolutionNavigation({ await searchClassicNavigation.expectNavItemExists('Home'); - // Check Content - // > Indices - await searchClassicNavigation.clickNavItem('Indices'); - await searchClassicNavigation.expectNavItemActive('Indices'); - await searchClassicNavigation.breadcrumbs.expectBreadcrumbExists('Content'); - await searchClassicNavigation.breadcrumbs.expectBreadcrumbExists('Elasticsearch indices'); // > Connectors await searchClassicNavigation.clickNavItem('Connectors'); await searchClassicNavigation.expectNavItemActive('Connectors'); @@ -127,5 +125,10 @@ export default function searchSolutionNavigation({ await expectNoPageReload(); }); + + it("should redirect to index management when clicking on 'Indices'", async () => { + await searchClassicNavigation.clickNavItem('Indices'); + await indexManagement.expectToBeOnIndicesManagement(); + }); }); } diff --git a/x-pack/test/functional_search/tests/search_index_detail.ts b/x-pack/test/functional_search/tests/search_index_detail.ts new file mode 100644 index 0000000000000..0e844d03c31d2 --- /dev/null +++ b/x-pack/test/functional_search/tests/search_index_detail.ts @@ -0,0 +1,313 @@ +/* + * 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'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { + searchIndexDetail, + common, + searchApiKeys, + searchNavigation, + indexManagement, + embeddedConsole, + header, + } = getPageObjects([ + 'searchIndexDetail', + 'common', + 'searchApiKeys', + 'searchNavigation', + 'common', + 'indexManagement', + 'embeddedConsole', + 'header', + ]); + const es = getService('es'); + const security = getService('security'); + const browser = getService('browser'); + const retry = getService('retry'); + const spaces = getService('spaces'); + + const deleteAllIndices = getService('esDeleteAllIndices'); + const indexName = 'test-my-index'; + + describe('index details page - search solution', function () { + describe('developer rights', function () { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the search solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'classic' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + await common.navigateToApp('enterpriseSearch'); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + await deleteAllIndices(indexName); + }); + describe('search index details page', () => { + before(async () => { + await es.indices.create({ index: indexName }); + await searchNavigation.navigateToIndexDetailPage(indexName); + }); + after(async () => { + await deleteAllIndices(indexName); + }); + it('can load index detail page', async () => { + await searchIndexDetail.expectIndexDetailPageHeader(); + await searchIndexDetail.expectSearchIndexDetailsTabsExists(); + await searchIndexDetail.expectAPIReferenceDocLinkExists(); + await searchIndexDetail.expectAPIReferenceDocLinkMissingInMoreOptions(); + }); + it('should have connection details', async () => { + await searchIndexDetail.expectConnectionDetails(); + }); + + describe('check code example texts', () => { + const indexNameCodeExample = 'test-my-index2'; + before(async () => { + await es.indices.create({ index: indexNameCodeExample }); + await searchNavigation.navigateToIndexDetailPage(indexNameCodeExample); + }); + + after(async () => { + await deleteAllIndices(indexNameCodeExample); + }); + + it('should have basic example texts', async () => { + await searchIndexDetail.expectHasSampleDocuments(); + }); + + it('should have other example texts when mapping changed', async () => { + await es.indices.putMapping({ + index: indexNameCodeExample, + properties: { + text: { type: 'text' }, + number: { type: 'integer' }, + }, + }); + await searchIndexDetail.expectSampleDocumentsWithCustomMappings(); + }); + }); + + describe('API key details', () => { + it('should show api key', async () => { + await searchApiKeys.deleteAPIKeys(); + await searchNavigation.navigateToIndexDetailPage(indexName); + // sometimes the API key exists in the cluster and its lost in sessionStorage + // if fails we retry to delete the API key and refresh the browser + await retry.try( + async () => { + await searchApiKeys.expectAPIKeyExists(); + }, + async () => { + await searchApiKeys.deleteAPIKeys(); + await browser.refresh(); + } + ); + await searchApiKeys.expectAPIKeyAvailable(); + const apiKey = await searchApiKeys.getAPIKeyFromUI(); + await searchIndexDetail.expectAPIKeyToBeVisibleInCodeBlock(apiKey); + }); + }); + + it('should have quick stats', async () => { + await searchIndexDetail.expectQuickStats(); + await searchIndexDetail.expectQuickStatsAIMappings(); + await es.indices.putMapping({ + index: indexName, + body: { + properties: { + my_field: { + type: 'dense_vector', + dims: 3, + }, + }, + }, + }); + await searchNavigation.navigateToIndexDetailPage(indexName); + await searchIndexDetail.expectQuickStatsAIMappingsToHaveVectorFields(); + }); + + it('should show code examples for adding documents', async () => { + await searchIndexDetail.expectAddDocumentCodeExamples(); + await searchIndexDetail.expectSelectedLanguage('python'); + await searchIndexDetail.codeSampleContainsValue('installCodeExample', 'pip install'); + await searchIndexDetail.selectCodingLanguage('javascript'); + await searchIndexDetail.codeSampleContainsValue('installCodeExample', 'npm install'); + await searchIndexDetail.selectCodingLanguage('curl'); + await searchIndexDetail.openConsoleCodeExample(); + await embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await embeddedConsole.clickEmbeddedConsoleControlBar(); + }); + + describe('With data', () => { + before(async () => { + await es.index({ + index: indexName, + refresh: true, + body: { + my_field: [1, 0, 1], + }, + }); + await searchNavigation.navigateToIndexDetailPage(indexName); + }); + it('should have index documents', async () => { + await searchIndexDetail.expectHasIndexDocuments(); + }); + it('menu action item should be replaced with playground', async () => { + await searchIndexDetail.expectActionItemReplacedWhenHasDocs(); + }); + it('should have link to API reference doc link in options menu', async () => { + await searchIndexDetail.clickMoreOptionsActionsButton(); + await searchIndexDetail.expectAPIReferenceDocLinkExistsInMoreOptions(); + }); + it('should have one document in quick stats', async () => { + await searchIndexDetail.expectQuickStatsToHaveDocumentCount(1); + }); + it('should have with data tabs', async () => { + await searchIndexDetail.expectTabsExists(); + await searchIndexDetail.expectUrlShouldChangeTo('data'); + }); + it('should be able to change tabs to mappings and mappings is shown', async () => { + await searchIndexDetail.changeTab('mappingsTab'); + await searchIndexDetail.expectUrlShouldChangeTo('mappings'); + await searchIndexDetail.expectMappingsComponentIsVisible(); + }); + it('should be able to change tabs to settings and settings is shown', async () => { + await searchIndexDetail.changeTab('settingsTab'); + await searchIndexDetail.expectUrlShouldChangeTo('settings'); + await searchIndexDetail.expectSettingsComponentIsVisible(); + }); + it('should be able to delete document', async () => { + await searchIndexDetail.changeTab('dataTab'); + await searchIndexDetail.clickFirstDocumentDeleteAction(); + await searchIndexDetail.expectAddDocumentCodeExamples(); + await searchIndexDetail.expectQuickStatsToHaveDocumentCount(0); + }); + }); + describe('has index actions enabled', () => { + before(async () => { + await es.index({ + index: indexName, + body: { + my_field: [1, 0, 1], + }, + }); + await searchNavigation.navigateToIndexDetailPage(indexName); + }); + + beforeEach(async () => { + await searchNavigation.navigateToIndexDetailPage(indexName); + }); + + it('delete document button is enabled', async () => { + await searchIndexDetail.expectDeleteDocumentActionToBeEnabled(); + }); + it('add field button is enabled', async () => { + await searchIndexDetail.changeTab('mappingsTab'); + await searchIndexDetail.expectAddFieldToBeEnabled(); + }); + it('edit settings button is enabled', async () => { + await searchIndexDetail.changeTab('settingsTab'); + await searchIndexDetail.expectEditSettingsToBeEnabled(); + }); + it('delete index button is enabled', async () => { + await searchIndexDetail.expectMoreOptionsActionButtonExists(); + await searchIndexDetail.clickMoreOptionsActionsButton(); + await searchIndexDetail.expectMoreOptionsOverviewMenuIsShown(); + await searchIndexDetail.expectDeleteIndexButtonExistsInMoreOptions(); + await searchIndexDetail.expectDeleteIndexButtonToBeEnabled(); + }); + }); + + describe('page loading error', () => { + before(async () => { + await searchNavigation.navigateToIndexDetailPage(indexName); + await deleteAllIndices(indexName); + }); + it('has page load error section', async () => { + await searchIndexDetail.expectPageLoadErrorExists(); + await searchIndexDetail.expectIndexNotFoundErrorExists(); + }); + it('reload button shows details page again', async () => { + await es.indices.create({ index: indexName }); + await searchIndexDetail.clickPageReload(); + await searchIndexDetail.expectIndexDetailPageHeader(); + }); + }); + describe('Index more options menu', () => { + before(async () => { + await searchNavigation.navigateToIndexDetailPage(indexName); + }); + it('shows action menu in actions popover', async () => { + await searchIndexDetail.expectMoreOptionsActionButtonExists(); + await searchIndexDetail.clickMoreOptionsActionsButton(); + await searchIndexDetail.expectMoreOptionsOverviewMenuIsShown(); + }); + it('should delete index', async () => { + await searchIndexDetail.expectDeleteIndexButtonExistsInMoreOptions(); + await searchIndexDetail.clickDeleteIndexButton(); + await searchIndexDetail.clickConfirmingDeleteIndex(); + }); + }); + }); + describe('index management index list page', () => { + before(async () => { + await es.indices.create({ index: indexName }); + await security.testUser.setRoles(['index_management_user']); + }); + beforeEach(async () => { + await searchNavigation.navigateToIndexManagementPage(); + // // Navigate to the indices tab + // await indexManagement.changeTabs('indicesTab'); + // await header.waitUntilLoadingHasFinished(); + }); + after(async () => { + await deleteAllIndices(indexName); + }); + describe('manage index action', () => { + beforeEach(async () => { + await indexManagement.manageIndex(indexName); + await indexManagement.manageIndexContextMenuExists(); + }); + it('navigates to overview tab', async () => { + await indexManagement.changeManageIndexTab('showOverviewIndexMenuButton'); + await searchIndexDetail.expectIndexDetailPageHeader(); + await searchIndexDetail.expectUrlShouldChangeTo('data'); + }); + + it('navigates to settings tab', async () => { + await indexManagement.changeManageIndexTab('showSettingsIndexMenuButton'); + await searchIndexDetail.expectIndexDetailPageHeader(); + await searchIndexDetail.expectUrlShouldChangeTo('settings'); + }); + it('navigates to mappings tab', async () => { + await indexManagement.changeManageIndexTab('showMappingsIndexMenuButton'); + await searchIndexDetail.expectIndexDetailPageHeader(); + await searchIndexDetail.expectUrlShouldChangeTo('mappings'); + }); + }); + describe('can view search index details', function () { + it('renders search index details with no documents', async () => { + await searchIndexDetail.openIndicesDetailFromIndexManagementIndicesListTable(0); + await searchIndexDetail.expectIndexDetailPageHeader(); + await searchIndexDetail.expectSearchIndexDetailsTabsExists(); + await searchIndexDetail.expectAPIReferenceDocLinkExists(); + }); + }); + }); + }); + }); +} diff --git a/x-pack/test/functional_search/tests/search_start.ts b/x-pack/test/functional_search/tests/search_start.ts new file mode 100644 index 0000000000000..91c3b4cf8fab6 --- /dev/null +++ b/x-pack/test/functional_search/tests/search_start.ts @@ -0,0 +1,189 @@ +/* + * 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 default function ({ getPageObjects, getService }: FtrProviderContext) { + const { common, searchApiKeys, searchStart, searchNavigation } = getPageObjects([ + 'searchStart', + 'common', + 'searchApiKeys', + 'searchNavigation', + ]); + const esDeleteAllIndices = getService('esDeleteAllIndices'); + const es = getService('es'); + const browser = getService('browser'); + const retry = getService('retry'); + const spaces = getService('spaces'); + + const deleteAllTestIndices = async () => { + await esDeleteAllIndices(['search-*', 'test-*']); + }; + + describe('Elasticsearch Start [Onboarding Empty State]', function () { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the search solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'classic' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + await common.navigateToApp('enterpriseSearch'); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + await deleteAllTestIndices(); + }); + + describe('Developer rights', function () { + beforeEach(async () => { + await deleteAllTestIndices(); + await searchApiKeys.deleteAPIKeys(); + await searchNavigation.navigateToElasticsearchStartPage(); + }); + + it('should support index creation flow with UI', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.expectCreateIndexUIView(); + await searchStart.expectCreateIndexButtonToBeEnabled(); + await searchStart.clickCreateIndexButton(); + await searchStart.expectToBeOnIndexDetailsPage(); + }); + + it('should support setting index name', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.expectIndexNameToExist(); + await searchStart.setIndexNameValue('INVALID_INDEX'); + await searchStart.expectCreateIndexButtonToBeDisabled(); + await searchStart.setIndexNameValue('test-index-name'); + await searchStart.expectCreateIndexButtonToBeEnabled(); + await searchStart.clickCreateIndexButton(); + await searchStart.expectToBeOnIndexDetailsPage(); + }); + + it('should redirect to index details when index is created via API', async () => { + await searchStart.expectToBeOnStartPage(); + await es.indices.create({ index: 'test-my-index' }); + await searchStart.expectToBeOnIndexDetailsPage(); + }); + + it('should redirect to index list when multiple indices are created via API', async () => { + await searchStart.expectToBeOnStartPage(); + await es.indices.create({ index: 'test-my-index-001' }); + await es.indices.create({ index: 'test-my-index-002' }); + await searchStart.expectToBeOnIndexListPage(); + }); + it('should redirect to indices list if single index exist on page load', async () => { + await searchNavigation.navigateToElasticsearchStartPage(); + await es.indices.create({ index: 'test-my-index-001' }); + await searchNavigation.navigateToElasticsearchStartPage(true); + await searchStart.expectToBeOnIndexListPage(); + }); + + it('should support switching between UI and Code Views', async () => { + await searchNavigation.navigateToElasticsearchStartPage(); + await searchStart.expectCreateIndexUIView(); + await searchStart.clickCodeViewButton(); + await searchStart.expectCreateIndexCodeView(); + await searchStart.clickUIViewButton(); + await searchStart.expectCreateIndexUIView(); + }); + + it('should show the api key in code view', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.clickCodeViewButton(); + // sometimes the API key exists in the cluster and its lost in sessionStorage + // if fails we retry to delete the API key and refresh the browser + await retry.try( + async () => { + await searchApiKeys.expectAPIKeyExists(); + }, + async () => { + await searchApiKeys.deleteAPIKeys(); + await browser.refresh(); + await searchStart.clickCodeViewButton(); + } + ); + await searchApiKeys.expectAPIKeyAvailable(); + + const apiKeyUI = await searchApiKeys.getAPIKeyFromUI(); + const apiKeySession = await searchApiKeys.getAPIKeyFromSessionStorage(); + + expect(apiKeyUI).to.eql(apiKeySession.encoded); + + // check that when browser is refreshed, the api key is still available + await browser.refresh(); + await searchStart.clickCodeViewButton(); + await searchApiKeys.expectAPIKeyAvailable(); + await searchStart.expectAPIKeyPreGenerated(); + const refreshBrowserApiKeyUI = await searchApiKeys.getAPIKeyFromUI(); + expect(refreshBrowserApiKeyUI).to.eql(apiKeyUI); + + // check that when api key is invalidated, a new one is generated + await searchApiKeys.invalidateAPIKey(apiKeySession.id); + await browser.refresh(); + await searchStart.clickCodeViewButton(); + await searchApiKeys.expectAPIKeyAvailable(); + const newApiKeyUI = await searchApiKeys.getAPIKeyFromUI(); + expect(newApiKeyUI).to.not.eql(apiKeyUI); + await searchStart.expectAPIKeyVisibleInCodeBlock(newApiKeyUI); + }); + + it('should explicitly ask to create api key when project already has an apikey', async () => { + await searchApiKeys.clearAPIKeySessionStorage(); + await searchApiKeys.createAPIKey(); + await searchStart.expectToBeOnStartPage(); + await searchStart.clickCodeViewButton(); + await searchApiKeys.createApiKeyFromFlyout(); + await searchApiKeys.expectAPIKeyAvailable(); + }); + + it('Same API Key should be present on start page and index detail view', async () => { + await searchStart.clickCodeViewButton(); + await searchApiKeys.expectAPIKeyAvailable(); + const apiKeyUI = await searchApiKeys.getAPIKeyFromUI(); + + await searchStart.clickUIViewButton(); + await searchStart.clickCreateIndexButton(); + await searchStart.expectToBeOnIndexDetailsPage(); + + await searchApiKeys.expectAPIKeyAvailable(); + const indexDetailsApiKey = await searchApiKeys.getAPIKeyFromUI(); + + expect(apiKeyUI).to.eql(indexDetailsApiKey); + }); + + it('should have file upload link', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.clickFileUploadLink(); + await searchStart.expectToBeOnMLFileUploadPage(); + }); + + it('should have close button', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.expectCloseCreateIndexButtonExists(); + await searchStart.clickCloseCreateIndexButton(); + await searchStart.expectToBeOnIndexListPage(); + }); + + it('should have skip button', async () => { + await searchStart.expectToBeOnStartPage(); + await searchStart.expectSkipButtonExists(); + await searchStart.clickSkipButton(); + await searchStart.expectToBeOnIndexListPage(); + }); + }); + }); +} From a89b6c17453efceec35d139c05f2e475c5639331 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Fri, 13 Dec 2024 20:42:07 +0000 Subject: [PATCH 04/29] the create index view when in search solution --- .../add_domain/add_domain_logic.test.ts | 2 +- .../search_index/indices/indices_nav.test.tsx | 181 ------------------ .../enterprise_search_content/routes.ts | 6 +- .../public/application/app_context.tsx | 2 + .../create_index/create_index_button.tsx | 16 +- 5 files changed, 19 insertions(+), 188 deletions(-) delete mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts index 9d20e50020015..83101c4b90fd6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/crawler/domain_management/add_domain/add_domain_logic.test.ts @@ -309,7 +309,7 @@ describe('AddDomainLogic', () => { expect(flashSuccessToast).toHaveBeenCalled(); expect(navigateToUrl).toHaveBeenCalledWith( - '/app/management/data/index_management/indices/index-name/domain_management/test-domain' + '/search_indices/index-name/domain_management/test-domain' ); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx deleted file mode 100644 index aeed49eca0fe0..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx +++ /dev/null @@ -1,181 +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 { setMockValues } from '../../../../__mocks__/kea_logic'; -import { mockUseRouteMatch, mockUseParams } from '../../../../__mocks__/react_router'; - -import { isConnectorIndex, isCrawlerIndex } from '../../../utils/indices'; - -import { mockIndexNameValues } from '../_mocks_/index_name_logic.mock'; - -jest.mock('../../../../shared/layout', () => ({ - generateNavLink: jest.fn(({ to }) => ({ href: to })), -})); -jest.mock('../../../utils/indices'); - -import { useIndicesNav } from './indices_nav'; - -describe('useIndicesNav', () => { - beforeEach(() => { - setMockValues(mockIndexNameValues); - mockUseRouteMatch.mockReturnValue(true); - mockUseParams.mockReturnValue({ indexName: 'index-name' }); - }); - - describe('returns empty', () => { - it('does not return index nav items if not on an index route', () => { - mockUseRouteMatch.mockReturnValueOnce(false); - expect(useIndicesNav()).toBeUndefined(); - }); - - it('does not return index nav items if index name is missing', () => { - mockUseParams.mockReturnValue({ indexName: '' }); - expect(useIndicesNav()).toBeUndefined(); - }); - }); - - describe('returns an array of EUI side nav items', () => { - const BASE_NAV = [ - { - id: 'indexName', - name: 'INDEX-NAME', - 'data-test-subj': 'IndexLabel', - href: '/app/management/data/index_management/indices/index-name', - items: [ - { - id: 'overview', - name: 'Overview', - href: '/app/management/data/index_management/indices/index-name/overview', - 'data-test-subj': 'IndexOverviewLink', - }, - { - id: 'documents', - name: 'Documents', - href: '/app/management/data/index_management/indices/index-name/documents', - 'data-test-subj': 'IndexDocumentsLink', - }, - { - id: 'index_mappings', - name: 'Index mappings', - href: '/app/management/data/index_management/indices/index-name/index_mappings', - 'data-test-subj': 'IndexIndexMappingsLink', - }, - ], - }, - ]; - - it('always returns an index label, overview, documents, index mapping link', () => { - expect(useIndicesNav()).toEqual(BASE_NAV); - }); - - it('returns pipelines with default navs when hasDefaultIngestPipeline is true', () => { - setMockValues({ - ...mockIndexNameValues, - productFeatures: { hasDefaultIngestPipeline: true }, - }); - - const pipelineItem = { - id: 'pipelines', - name: 'Pipelines', - href: '/search_indices/index-name/pipelines', - 'data-test-subj': 'IndexPipelineLink', - }; - const baseNavWithPipelines = BASE_NAV.map((navItem) => ({ - ...navItem, - items: [...navItem.items, pipelineItem], - })); - - expect(useIndicesNav()).toEqual(baseNavWithPipelines); - }); - - describe('connectors nav', () => { - it('returns connectors nav with default navs when isConnectorIndex is true', () => { - jest.mocked(isConnectorIndex).mockReturnValueOnce(true); - - const configuration = { - 'data-test-subj': 'IndexConnectorsConfigurationLink', - id: 'connectors_configuration', - name: 'Configuration', - href: '/search_indices/index-name/configuration', - }; - const scheduling = { - 'data-test-subj': 'IndexSchedulingLink', - id: 'scheduling', - name: 'Scheduling', - href: '/search_indices/index-name/scheduling', - }; - const baseNavWithConnectors = BASE_NAV.map((navItem) => ({ - ...navItem, - items: [...navItem.items, configuration, scheduling], - })); - - expect(useIndicesNav()).toEqual(baseNavWithConnectors); - }); - - it('returns connectors nav with sync rules with default navs when isConnectorIndex is true and hasFilteringFeature is true', () => { - jest.mocked(isConnectorIndex).mockReturnValueOnce(true); - setMockValues({ ...mockIndexNameValues, hasFilteringFeature: true }); - - const configuration = { - 'data-test-subj': 'IndexConnectorsConfigurationLink', - id: 'connectors_configuration', - name: 'Configuration', - href: '/search_indices/index-name/configuration', - }; - const syncRules = { - 'data-test-subj': 'IndexSyncRulesLink', - id: 'syncRules', - name: 'Sync rules', - href: '/search_indices/index-name/sync_rules', - }; - const scheduling = { - 'data-test-subj': 'IndexSchedulingLink', - id: 'scheduling', - name: 'Scheduling', - href: '/search_indices/index-name/scheduling', - }; - const baseNavWithConnectors = BASE_NAV.map((navItem) => ({ - ...navItem, - items: [...navItem.items, configuration, syncRules, scheduling], - })); - - expect(useIndicesNav()).toEqual(baseNavWithConnectors); - }); - }); - - describe('crawlers nav', () => { - it('returns crawlers nav with default navs when isCrawlerIndex is true', () => { - jest.mocked(isCrawlerIndex).mockReturnValueOnce(true); - - const domainManagement = { - 'data-test-subj': 'IndexDomainManagementLink', - id: 'domain_management', - name: 'Manage Domains', - href: '/search_indices/index-name/domain_management', - }; - const configuration = { - 'data-test-subj': 'IndexCrawlerConfigurationLink', - id: 'crawler_configuration', - name: 'Configuration', - href: '/search_indices/index-name/crawler_configuration', - }; - const scheduling = { - 'data-test-subj': 'IndexCrawlerSchedulingLink', - id: 'crawler_scheduling', - name: 'Scheduling', - href: '/search_indices/index-name/scheduling', - }; - const baseNavWithCrawlers = BASE_NAV.map((navItem) => ({ - ...navItem, - items: [...navItem.items, domainManagement, configuration, scheduling], - })); - - expect(useIndicesNav()).toEqual(baseNavWithCrawlers); - }); - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts index a2985357c8abd..092b60bf7666f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/routes.ts @@ -10,12 +10,12 @@ export const ROOT_PATH = '/'; export const SETUP_GUIDE_PATH = '/setup_guide'; export const ERROR_STATE_PATH = '/error_state'; -export const INDEX_MANAGEMENT_INDICES_PATH = `/app/management/data/index_management/indices`; +export const SEARCH_INDICES_PATH = `${ROOT_PATH}search_indices`; export const CONNECTORS_PATH = `${ROOT_PATH}connectors`; export const CRAWLERS_PATH = `${ROOT_PATH}crawlers`; export const SETTINGS_PATH = `${ROOT_PATH}settings`; -export const NEW_INDEX_PATH = `${INDEX_MANAGEMENT_INDICES_PATH}/new_index`; +export const NEW_INDEX_PATH = `${SEARCH_INDICES_PATH}/new_index`; export const NEW_API_PATH = `${NEW_INDEX_PATH}/api`; export const NEW_ES_INDEX_PATH = `${NEW_INDEX_PATH}/elasticsearch`; export const NEW_DIRECT_UPLOAD_PATH = `${NEW_INDEX_PATH}/upload`; @@ -26,7 +26,7 @@ export const NEW_CRAWLER_PATH = `${CRAWLERS_PATH}/new_crawler`; export const NEW_INDEX_SELECT_CONNECTOR_NATIVE_PATH = `${CONNECTORS_PATH}/select_connector?filter=native`; export const NEW_INDEX_SELECT_CONNECTOR_CLIENTS_PATH = `${CONNECTORS_PATH}/select_connector?filter=connector_clients`; -export const SEARCH_INDEX_PATH = `${INDEX_MANAGEMENT_INDICES_PATH}/:indexName`; +export const SEARCH_INDEX_PATH = `${SEARCH_INDICES_PATH}/:indexName`; export const SEARCH_INDEX_TAB_PATH = `${SEARCH_INDEX_PATH}/:tabId`; export const SEARCH_INDEX_TAB_DETAIL_PATH = `${SEARCH_INDEX_TAB_PATH}/:detailId`; export const SEARCH_INDEX_CRAWLER_DOMAIN_DETAIL_PATH = `${SEARCH_INDEX_TAB_PATH}/:domainId`; diff --git a/x-pack/plugins/index_management/public/application/app_context.tsx b/x-pack/plugins/index_management/public/application/app_context.tsx index 3573ae33812d9..a6fb91c7925c1 100644 --- a/x-pack/plugins/index_management/public/application/app_context.tsx +++ b/x-pack/plugins/index_management/public/application/app_context.tsx @@ -19,6 +19,7 @@ import { HttpSetup, IUiSettingsClient, OverlayStart, + ChromeStart, } from '@kbn/core/public'; import type { MlPluginStart } from '@kbn/ml-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; @@ -43,6 +44,7 @@ export interface AppDependencies { http: HttpSetup; i18n: I18nStart; theme: ThemeServiceStart; + chrome: ChromeStart; }; plugins: { usageCollection: UsageCollectionSetup; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx index e7201ce5d44b3..4200d9b0d2462 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx @@ -10,7 +10,9 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import { EuiButton } from '@elastic/eui'; +import useObservable from 'react-use/lib/useObservable'; import { CreateIndexModal } from './create_index_modal'; +import { useAppContext } from '../../../../app_context'; export interface CreateIndexButtonProps { loadIndices: () => void; @@ -20,9 +22,17 @@ export interface CreateIndexButtonProps { export const CreateIndexButton = ({ loadIndices, share }: CreateIndexButtonProps) => { const [createIndexModalOpen, setCreateIndexModalOpen] = useState(false); const createIndexUrl = share?.url.locators.get('SEARCH_CREATE_INDEX')?.useUrl({}); - const actionProp = createIndexUrl - ? { href: createIndexUrl } - : { onClick: () => setCreateIndexModalOpen(true) }; + + const { + core: { chrome }, + } = useAppContext(); + + const activeSolutionId = useObservable(chrome.getActiveSolutionNavId$()); + + const actionProp = + createIndexUrl && activeSolutionId === 'es' + ? { href: createIndexUrl } + : { onClick: () => setCreateIndexModalOpen(true) }; return ( <> From 66c230284b5da8f87c3d971d92760747b0abb362 Mon Sep 17 00:00:00 2001 From: Joseph McElroy Date: Mon, 16 Dec 2024 10:09:43 +0000 Subject: [PATCH 05/29] updates to ftrs --- .../page_objects/search_navigation.ts | 23 +++++++------------ .../tests/classic_navigation.ts | 2 +- .../tests/embedded_console.ts | 20 ++++++++++++++++ .../tests/search_index_detail.ts | 18 +++++++++------ .../functional_search/tests/search_start.ts | 15 +++++++++--- 5 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 x-pack/test/functional_search/tests/embedded_console.ts diff --git a/x-pack/test/functional/page_objects/search_navigation.ts b/x-pack/test/functional/page_objects/search_navigation.ts index 087a5152cbe7d..290674776f362 100644 --- a/x-pack/test/functional/page_objects/search_navigation.ts +++ b/x-pack/test/functional/page_objects/search_navigation.ts @@ -12,23 +12,14 @@ export function SearchNavigationServiceProvider({ getPageObjects, }: FtrProviderContext) { const retry = getService('retry'); - const { common, indexManagement } = getPageObjects(['common', 'indexManagement']); + const { common, indexManagement, solutionNavigation } = getPageObjects([ + 'common', + 'indexManagement', + 'solutionNavigation', + ]); const testSubjects = getService('testSubjects'); return { - async navigateToLandingPage() { - await retry.tryForTime(60 * 1000, async () => { - await common.navigateToApp('landingPage'); - // Wait for the side nav, since the landing page will sometimes redirect to index management now - await testSubjects.existOrFail('svlSearchSideNav', { timeout: 2000 }); - }); - }, - async navigateToGettingStartedPage() { - await retry.tryForTime(60 * 1000, async () => { - await common.navigateToApp('serverlessElasticsearch'); - await testSubjects.existOrFail('svlSearchOverviewPage', { timeout: 2000 }); - }); - }, async navigateToElasticsearchStartPage(expectRedirect: boolean = false) { await retry.tryForTime(60 * 1000, async () => { await common.navigateToApp('elasticsearch/start', { @@ -55,7 +46,9 @@ export function SearchNavigationServiceProvider({ async navigateToIndexManagementPage() { await retry.tryForTime(60 * 1000, async () => { - await common.navigateToApp('management/data/index_management'); + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); await indexManagement.expectToBeOnIndicesManagement(); }); }, diff --git a/x-pack/test/functional_search/tests/classic_navigation.ts b/x-pack/test/functional_search/tests/classic_navigation.ts index 2cc8457a42e8d..f8b14d79afbbe 100644 --- a/x-pack/test/functional_search/tests/classic_navigation.ts +++ b/x-pack/test/functional_search/tests/classic_navigation.ts @@ -44,7 +44,7 @@ export default function searchSolutionNavigation({ await searchClassicNavigation.expectAllNavItems([ { id: 'Home', label: 'Home' }, { id: 'Content', label: 'Content' }, - { id: 'Indices', label: 'Indices' }, + { id: 'Indices', label: 'Index Management' }, { id: 'Connectors', label: 'Connectors' }, { id: 'Crawlers', label: 'Web Crawlers' }, { id: 'Build', label: 'Build' }, diff --git a/x-pack/test/functional_search/tests/embedded_console.ts b/x-pack/test/functional_search/tests/embedded_console.ts new file mode 100644 index 0000000000000..04153d4a39ee6 --- /dev/null +++ b/x-pack/test/functional_search/tests/embedded_console.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 { FtrProviderContext } from '../ftr_provider_context'; + +type PageObjects = Pick, 'embeddedConsole'>; + +export async function testHasEmbeddedConsole(pageObjects: PageObjects) { + await pageObjects.embeddedConsole.expectEmbeddedConsoleControlBarExists(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleHaveFullscreenToggle(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); +} diff --git a/x-pack/test/functional_search/tests/search_index_detail.ts b/x-pack/test/functional_search/tests/search_index_detail.ts index 0e844d03c31d2..17ccb561ff7b4 100644 --- a/x-pack/test/functional_search/tests/search_index_detail.ts +++ b/x-pack/test/functional_search/tests/search_index_detail.ts @@ -5,6 +5,7 @@ * 2.0. */ import { FtrProviderContext } from '../ftr_provider_context'; +import { testHasEmbeddedConsole } from './embedded_console'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const { @@ -14,7 +15,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { searchNavigation, indexManagement, embeddedConsole, - header, } = getPageObjects([ 'searchIndexDetail', 'common', @@ -23,7 +23,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'common', 'indexManagement', 'embeddedConsole', - 'header', ]); const es = getService('es'); const security = getService('security'); @@ -46,9 +45,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); // Create a space with the search solution and navigate to its home page - ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'classic' })); + ({ cleanUp, space: spaceCreated } = await spaces.create({ + name: 'search-ftr', + solution: 'es', + })); await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); - await common.navigateToApp('enterpriseSearch'); }); after(async () => { @@ -56,6 +57,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cleanUp(); await deleteAllIndices(indexName); }); + describe('search index details page', () => { before(async () => { await es.indices.create({ index: indexName }); @@ -70,6 +72,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await searchIndexDetail.expectAPIReferenceDocLinkExists(); await searchIndexDetail.expectAPIReferenceDocLinkMissingInMoreOptions(); }); + it('should have connection details', async () => { await searchIndexDetail.expectConnectionDetails(); }); @@ -85,6 +88,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await deleteAllIndices(indexNameCodeExample); }); + it('should have embedded dev console', async () => { + await testHasEmbeddedConsole({ embeddedConsole }); + }); + it('should have basic example texts', async () => { await searchIndexDetail.expectHasSampleDocuments(); }); @@ -270,9 +277,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); beforeEach(async () => { await searchNavigation.navigateToIndexManagementPage(); - // // Navigate to the indices tab - // await indexManagement.changeTabs('indicesTab'); - // await header.waitUntilLoadingHasFinished(); }); after(async () => { await deleteAllIndices(indexName); diff --git a/x-pack/test/functional_search/tests/search_start.ts b/x-pack/test/functional_search/tests/search_start.ts index 91c3b4cf8fab6..b96ea0230e24c 100644 --- a/x-pack/test/functional_search/tests/search_start.ts +++ b/x-pack/test/functional_search/tests/search_start.ts @@ -7,13 +7,15 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; +import { testHasEmbeddedConsole } from './embedded_console'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const { common, searchApiKeys, searchStart, searchNavigation } = getPageObjects([ + const { common, searchApiKeys, searchStart, searchNavigation, embeddedConsole } = getPageObjects([ 'searchStart', 'common', 'searchApiKeys', 'searchNavigation', + 'embeddedConsole', ]); const esDeleteAllIndices = getService('esDeleteAllIndices'); const es = getService('es'); @@ -36,9 +38,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); // Create a space with the search solution and navigate to its home page - ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'classic' })); + ({ cleanUp, space: spaceCreated } = await spaces.create({ + name: 'search-ftr', + solution: 'es', + })); await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); - await common.navigateToApp('enterpriseSearch'); }); after(async () => { @@ -54,6 +58,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await searchNavigation.navigateToElasticsearchStartPage(); }); + it('should have embedded dev console', async () => { + await searchStart.expectToBeOnStartPage(); + await testHasEmbeddedConsole({ embeddedConsole }); + }); + it('should support index creation flow with UI', async () => { await searchStart.expectToBeOnStartPage(); await searchStart.expectCreateIndexUIView(); From a5f5f6d78b79524e40692c231ad6c0a3352a46d5 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:37:24 +0000 Subject: [PATCH 06/29] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- x-pack/plugins/enterprise_search/public/navigation_tree.ts | 1 - x-pack/plugins/enterprise_search/public/plugin.ts | 6 +----- .../public/components/create_index/create_index_page.tsx | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts index 59cee65bfbbc3..5e44041dabdfb 100644 --- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -18,7 +18,6 @@ import { i18n } from '@kbn/i18n'; import type { AddSolutionNavigationArg } from '@kbn/navigation-plugin/public'; import { SEARCH_APPLICATIONS_PATH } from './applications/applications/routes'; -import { SEARCH_INDICES_PATH } from './applications/enterprise_search_content/routes'; export interface DynamicSideNavItems { appSearch?: Array>; diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 9dd91decce937..39d72db240240 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -59,11 +59,7 @@ import { hasEnterpriseLicense } from '../common/utils/licensing'; import { ENGINES_PATH } from './applications/app_search/routes'; import { SEARCH_APPLICATIONS_PATH } from './applications/applications/routes'; -import { - CONNECTORS_PATH, - INDEX_MANAGEMENT_INDICES_PATH, - CRAWLERS_PATH, -} from './applications/enterprise_search_content/routes'; +import { CONNECTORS_PATH, CRAWLERS_PATH } from './applications/enterprise_search_content/routes'; import { docLinks } from './applications/shared/doc_links'; import type { DynamicSideNavItems } from './navigation_tree'; diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx index 180e5ee8786a6..1466fbdcec6a6 100644 --- a/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx @@ -8,7 +8,7 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui'; +import { EuiLoadingLogo } from '@elastic/eui'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import { useKibana } from '../../hooks/use_kibana'; From d30e044cad6f1b65267524415740735f45e42e22 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 16 Dec 2024 18:26:07 +0100 Subject: [PATCH 07/29] Fix use search nav after recent updates --- .../enterprise_search/public/applications/shared/layout/nav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 45a15bbac9a22..eed071449be72 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 @@ -39,7 +39,7 @@ export const useEnterpriseSearchNav = (alwaysReturn = false) => { }, {} as Record); return generateSideNavItems(baseNavItems, deepLinks); - }, [productAccess]); + }, []); if (!isSidebarEnabled && !alwaysReturn) return undefined; From 1961431ca932206f2305faf650e220fb48a5baff Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 17 Dec 2024 15:59:28 +0100 Subject: [PATCH 08/29] Update solution navigation ftr --- .../tests/solution_navigation.ts | 61 ++++++------------- 1 file changed, 19 insertions(+), 42 deletions(-) diff --git a/x-pack/test/functional_search/tests/solution_navigation.ts b/x-pack/test/functional_search/tests/solution_navigation.ts index 03a4614017ba2..8ed4f94760b11 100644 --- a/x-pack/test/functional_search/tests/solution_navigation.ts +++ b/x-pack/test/functional_search/tests/solution_navigation.ts @@ -11,7 +11,11 @@ export default function searchSolutionNavigation({ getPageObjects, getService, }: FtrProviderContext) { - const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const { common, solutionNavigation, indexManagement } = getPageObjects([ + 'common', + 'indexManagement', + 'solutionNavigation', + ]); const spaces = getService('spaces'); const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); @@ -59,8 +63,6 @@ export default function searchSolutionNavigation({ await solutionNavigation.sidenav.expectLinkExists({ text: 'Search applications' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Behavioral Analytics' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' }); - await solutionNavigation.sidenav.expectLinkExists({ text: 'App Search' }); - await solutionNavigation.sidenav.expectLinkExists({ text: 'Workplace Search' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Other tools' }); }); @@ -117,15 +119,16 @@ export default function searchSolutionNavigation({ // check the Content // > Indices section await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + deepLinkId: 'management:index_management', }); await solutionNavigation.sidenav.expectLinkActive({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + deepLinkId: 'management:index_management', }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Content' }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Deployment' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Stack Management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Index Management' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + text: 'Indices', }); // > Connectors await solutionNavigation.sidenav.clickLink({ @@ -210,36 +213,6 @@ export default function searchSolutionNavigation({ deepLinkId: 'searchInferenceEndpoints:inferenceEndpoints', }); - // check Enterprise Search - // > App Search - await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'appSearch:engines', - }); - await solutionNavigation.sidenav.expectLinkActive({ - deepLinkId: 'appSearch:engines', - }); - // ent-search node not running for FTRs, so we see setup guide without breadcrumbs - // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - // text: 'App Search', - // }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'appSearch:engines', - }); - // > Workplace Search - await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'workplaceSearch', - }); - await solutionNavigation.sidenav.expectLinkActive({ - deepLinkId: 'workplaceSearch', - }); - // ent-search node not running for FTRs, so we see setup guide without breadcrumbs - // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - // text: 'Workplace Search', - // }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'workplaceSearch', - }); - // Other tools await solutionNavigation.sidenav.openSection('search_project_nav.otherTools'); // > Maps @@ -289,6 +262,13 @@ export default function searchSolutionNavigation({ await expectNoPageReload(); }); + it("should redirect to index management when clicking on 'Indices'", async () => { + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'management:index_management', + }); + await indexManagement.expectToBeOnIndicesManagement(); + }); + it('renders only expected items', async () => { await solutionNavigation.sidenav.openSection('search_project_nav.otherTools'); await solutionNavigation.sidenav.openSection('project_settings_project_nav'); @@ -300,7 +280,7 @@ export default function searchSolutionNavigation({ 'discover', 'dashboards', 'content', - 'enterpriseSearchContent:searchIndices', + 'management:index_management', 'enterpriseSearchContent:connectors', 'enterpriseSearchContent:webCrawlers', 'build', @@ -309,9 +289,6 @@ export default function searchSolutionNavigation({ 'enterpriseSearchAnalytics', 'relevance', 'searchInferenceEndpoints:inferenceEndpoints', - 'entsearch', - 'appSearch:engines', - 'workplaceSearch', 'otherTools', 'maps', 'canvas', From 748e0813432a207a7160c5b16979fadd33728610 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Wed, 18 Dec 2024 16:53:25 +0100 Subject: [PATCH 09/29] feat(x-pack): Update navigation tree definition and test cases --- .../enterprise_search/public/navigation_tree.ts | 2 +- .../setup_page/create_index_button.test.tsx | 5 +++-- .../functional/page_objects/search_index_detail.ts | 4 ++-- .../functional/page_objects/search_navigation.ts | 12 ++++++------ .../functional_search/tests/search_index_detail.ts | 4 ++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/plugins/enterprise_search/public/navigation_tree.ts index e6fa8a2ec0806..d8311a5e0710a 100644 --- a/x-pack/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/plugins/enterprise_search/public/navigation_tree.ts @@ -76,7 +76,7 @@ export const getNavigationTreeDefinition = ({ id: 'es', navigationTree$: dynamicItems$.pipe( debounceTime(10), - map(({ indices, searchApps, collections }) => { + map(({ searchApps, collections }) => { const navTree: NavigationTreeDefinition = { body: [ { diff --git a/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.test.tsx b/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.test.tsx index 485bb5eb5df55..ed9799abc2578 100644 --- a/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.test.tsx +++ b/x-pack/plugins/search_playground/public/components/setup_page/create_index_button.test.tsx @@ -56,7 +56,8 @@ describe('CreateIndexButton', () => { url: { locators: { get: jest.fn().mockReturnValue({ - getUrl: jest.fn().mockReturnValue('mock-create-index-url'), + getUrl: jest.fn().mockReturnValue('mock-url'), + getRedirectUrl: jest.fn().mockReturnValue('mock-shown-url'), }), }, }, @@ -72,7 +73,7 @@ describe('CreateIndexButton', () => { fireEvent.click(createIndexButton); await waitFor(() => { - expect(navigateToUrl).toHaveBeenCalledWith('mock-create-index-url'); + expect(navigateToUrl).toHaveBeenCalledWith('mock-url'); }); }); }); diff --git a/x-pack/test/functional/page_objects/search_index_detail.ts b/x-pack/test/functional/page_objects/search_index_detail.ts index afde1c065677e..7440ee1c94c41 100644 --- a/x-pack/test/functional/page_objects/search_index_detail.ts +++ b/x-pack/test/functional/page_objects/search_index_detail.ts @@ -38,9 +38,9 @@ export function SearchIndexDetailProvider({ getService }: FtrProviderContext) { 'QuickStatsDocumentCount' ); expect(await quickStatsDocumentElem.getVisibleText()).to.contain('Document count\n0'); - expect(await quickStatsDocumentElem.getVisibleText()).not.to.contain('Index Size\n0b'); + expect(await quickStatsDocumentElem.getVisibleText()).not.to.contain('Index Size'); await quickStatsDocumentElem.click(); - expect(await quickStatsDocumentElem.getVisibleText()).to.contain('Index Size\n0b'); + expect(await quickStatsDocumentElem.getVisibleText()).to.contain('Index Size\n227b'); }, async expectQuickStatsToHaveDocumentCount(count: number) { diff --git a/x-pack/test/functional/page_objects/search_navigation.ts b/x-pack/test/functional/page_objects/search_navigation.ts index 290674776f362..9bbfbeba33f15 100644 --- a/x-pack/test/functional/page_objects/search_navigation.ts +++ b/x-pack/test/functional/page_objects/search_navigation.ts @@ -12,10 +12,10 @@ export function SearchNavigationServiceProvider({ getPageObjects, }: FtrProviderContext) { const retry = getService('retry'); - const { common, indexManagement, solutionNavigation } = getPageObjects([ + const { common, indexManagement, header } = getPageObjects([ + 'header', 'common', 'indexManagement', - 'solutionNavigation', ]); const testSubjects = getService('testSubjects'); @@ -45,10 +45,10 @@ export function SearchNavigationServiceProvider({ }, async navigateToIndexManagementPage() { - await retry.tryForTime(60 * 1000, async () => { - await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'enterpriseSearchContent:searchIndices', - }); + await retry.tryForTime(10 * 1000, async () => { + await common.navigateToApp(`indexManagement`); + await indexManagement.changeTabs('indicesTab'); + await header.waitUntilLoadingHasFinished(); await indexManagement.expectToBeOnIndicesManagement(); }); }, diff --git a/x-pack/test/functional_search/tests/search_index_detail.ts b/x-pack/test/functional_search/tests/search_index_detail.ts index 17ccb561ff7b4..b725e4376b25f 100644 --- a/x-pack/test/functional_search/tests/search_index_detail.ts +++ b/x-pack/test/functional_search/tests/search_index_detail.ts @@ -16,11 +16,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { indexManagement, embeddedConsole, } = getPageObjects([ + 'header', 'searchIndexDetail', 'common', 'searchApiKeys', 'searchNavigation', - 'common', 'indexManagement', 'embeddedConsole', ]); @@ -270,7 +270,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); }); - describe('index management index list page', () => { + describe.skip('index management index list page', () => { before(async () => { await es.indices.create({ index: indexName }); await security.testUser.setRoles(['index_management_user']); From 424f7b1c72084366fa96946ca7fa6cd429af7da3 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Wed, 18 Dec 2024 17:39:03 +0100 Subject: [PATCH 10/29] feat(x-pack): Add search navigation plugin dependency --- x-pack/plugins/search_indices/public/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/search_indices/public/types.ts b/x-pack/plugins/search_indices/public/types.ts index 105e496c179c8..209d937bb97d1 100644 --- a/x-pack/plugins/search_indices/public/types.ts +++ b/x-pack/plugins/search_indices/public/types.ts @@ -7,6 +7,7 @@ import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; import type { ConsolePluginSetup, ConsolePluginStart } from '@kbn/console-plugin/public'; +import type { SearchNavigationPluginStart } from '@kbn/search-navigation/public'; import type { AppMountParameters, CoreStart } from '@kbn/core/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { From 9ac52e45651dad406d06c99ff7b703cbc2adddfb Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Dec 2024 21:57:12 +0000 Subject: [PATCH 11/29] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/search_indices/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index 341dd230cee5f..885450621f8bd 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -39,7 +39,8 @@ "@kbn/deeplinks-search", "@kbn/core-chrome-browser", "@kbn/serverless", - "@kbn/utility-types" + "@kbn/utility-types", + "@kbn/search-navigation" ], "exclude": [ "target/**/*", From a4054a74d1c9857265d6b3c06f685d047f8db67c Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 00:05:08 +0100 Subject: [PATCH 12/29] Add translations --- .../translations/translations/fr-FR.json | 28 ++++++------------- .../translations/translations/ja-JP.json | 28 ++++++------------- .../translations/translations/zh-CN.json | 28 ++++++------------- 3 files changed, 27 insertions(+), 57 deletions(-) diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 07bc02dbceec3..267a5c4a28b5c 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -7261,6 +7261,14 @@ "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "La suppression d'alertes est configurée mais elle ne sera pas appliquée en raison d'une licence insuffisante", "securitySolutionPackages.alertSuppressionRuleForm.upsell": "La suppression d'alertes est activée avec la licence {requiredLicense} ou supérieure", "securitySolutionPackages.beta.label": "Bêta", + "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "Échec", + "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "S. O.", + "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "Réussite", + "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "Échec de la recherche", + "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "Niveau de sécurité du cloud", + "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "Résultats", + "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "Règles", + "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Gestion des vulnérabilités natives du cloud", "securitySolutionPackages.dataTable.ariaLabel": "Alertes", "securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "Supprimer la colonne", "securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "Résumé des événements", @@ -7590,6 +7598,7 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "ID du localisateur non spécifié. Spécifiez le paramètre de recherche \"l\" dans l'URL ; ce devrait être un ID de localisateur existant.", "share.urlService.redirect.RedirectManager.missingParamParams": "Paramètres du localisateur non spécifiés. Spécifiez le paramètre de recherche \"p\" dans l'URL ; ce devrait être un objet sérialisé JSON des paramètres du localisateur.", "share.urlService.redirect.RedirectManager.missingParamVersion": "Version des paramètres du localisateur non spécifiée. Spécifiez le paramètre de recherche \"v\" dans l'URL ; ce devrait être la version de Kibana au moment de la génération des paramètres du localisateur.", + "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "Erreur inconnue", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "Ajouter depuis la bibliothèque", "sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "Il y a plus de 120 boutons supplémentaires. Nous vous invitons à limiter le nombre de boutons.", "sharedUXPackages.card.noData.description": "Utilisez Elastic Agent pour collecter de manière simple et unifiée les données de vos machines.", @@ -14597,7 +14606,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "Vulnérabilités", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "Vulnérabilités", "xpack.csp.common.component.multiSelectFilter.searchWord": "Recherche", - "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "Erreur inconnue", "xpack.csp.compactFormattedNumber.naTitle": "S. O.", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} échecs et {passed} réussites de résultats", "xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "Échec des résultats", @@ -14612,9 +14620,6 @@ "xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "Afficher les règles CSP", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "Afficher le tableau de bord CNVM", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "Afficher les résultats des vulnérabilités", - "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "Échec", - "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "S. O.", - "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "Réussite", "xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "La fonctionnalité Lancer Cloud Shell pour obtenir les informations d'identification de façon automatisée n’est pas pris en charge dans la version d'intégration actuelle. Veuillez effectuer une mise à niveau vers la dernière version pour activer Lancer Cloud Shell pour les informations d'identification automatisées.", "xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS", "xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS", @@ -14698,7 +14703,6 @@ "xpack.csp.findings.distributionBar.totalPassedLabel": "Réussite des résultats", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "Une erreur s’est produite lors de la récupération des résultats de recherche.", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "Afficher le message d'erreur", - "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "Échec de la recherche", "xpack.csp.findings.findingsFlyout.calloutTitle": "Certains champs ne sont pas fournis par {vendor}", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "ID ressource", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "Nom de ressource", @@ -14868,10 +14872,6 @@ "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", "xpack.csp.kspmIntegration.vanillaOption.nameTitle": "Autogéré", - "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "Niveau de sécurité du cloud", - "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "Résultats", - "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "Règles", - "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Gestion des vulnérabilités natives du cloud", "xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "Évaluation du niveau en cours", "xpack.csp.noFindingsStates.indexing.indexingDescription": "En attente de la collecte et de l'indexation des données. Revenez plus tard pour voir vos résultats", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "La collecte des résultats prend plus de temps que prévu. {docs}.", @@ -18242,16 +18242,6 @@ "xpack.enterpriseSearch.nav.relevanceTitle": "Pertinence", "xpack.enterpriseSearch.nav.searchApplication.contentTitle": "Contenu", "xpack.enterpriseSearch.nav.searchApplication.docsExplorerTitle": "Explorateur de documents", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.connectorsConfigurationLabel": "Configuration", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerConfigurationLabel": "Configuration", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerSchedulingLabel": "Planification", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.documentsTitle": "Documents", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.domainManagementLabel": "Gérer les domaines", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.indexMappingsTitle": "Mappings d'index", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.overviewTitle": "Aperçu", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.pipelinesLabel": "Pipelines", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.schedulingTitle": "Planification", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.syncRulesLabel": "Règles de synchronisation", "xpack.enterpriseSearch.navigation.applicationsSearchApplicationsLinkLabel": "Applications de recherche", "xpack.enterpriseSearch.navigation.appSearchEnginesLinkLabel": "Moteurs", "xpack.enterpriseSearch.navigation.contentConnectorsLinkLabel": "Connecteurs", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 8641da40c1e3c..4889a1bebcb58 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -7139,6 +7139,14 @@ "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "アラート非表示が構成されていますが、ライセンス不足のため適用されません", "securitySolutionPackages.alertSuppressionRuleForm.upsell": "アラートの非表示は、{requiredLicense}ライセンス以上で有効です", "securitySolutionPackages.beta.label": "ベータ", + "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失敗", + "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "N/A", + "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "合格", + "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "検索失敗", + "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "クラウドセキュリティ態勢", + "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "調査結果", + "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "ルール", + "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Cloud Native Vulnerability Management", "securitySolutionPackages.dataTable.ariaLabel": "アラート", "securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "列を削除", "securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "イベント概要", @@ -7467,6 +7475,7 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "ロケーターIDが指定されていません。URLで「l」検索パラメーターを指定します。これは既存のロケーターIDにしてください。", "share.urlService.redirect.RedirectManager.missingParamParams": "ロケーターパラメーターが指定されていません。URLで「p」検索パラメーターを指定します。これはロケーターパラメーターのJSONシリアル化オブジェクトにしてください。", "share.urlService.redirect.RedirectManager.missingParamVersion": "ロケーターパラメーターバージョンが指定されていません。URLで「v」検索パラメーターを指定します。これはロケーターパラメーターが生成されたときのKibanaのリリースバージョンです。", + "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "不明なエラー", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "ライブラリから追加", "sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "120以上のボタンがあります。ボタンの数を制限することを検討してください。", "sharedUXPackages.card.noData.description": "Elasticエージェントを使用すると、シンプルで統一された方法でコンピューターからデータを収集するできます。", @@ -14464,7 +14473,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "脆弱性", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "脆弱性", "xpack.csp.common.component.multiSelectFilter.searchWord": "検索", - "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "不明なエラー", "xpack.csp.compactFormattedNumber.naTitle": "N/A", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed}が失敗し、{passed}が調査結果に合格しました", "xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "失敗した調査結果", @@ -14479,9 +14487,6 @@ "xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "CSPルールを表示", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "CNVMダッシュボードを表示", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "脆弱性の調査結果を表示", - "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失敗", - "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "N/A", - "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "合格", "xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "Launch Cloud ShellLaunch Cloud Formation for Automated Credentialsは、現在の統合バージョンではサポートされていません。Launch Cloud Shell for Automated Credentialsを有効化するには、最新バージョンにアップグレードしてください。", "xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS", "xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS", @@ -14564,7 +14569,6 @@ "xpack.csp.findings.distributionBar.totalPassedLabel": "合格した調査結果", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "検索結果の取得中にエラーが発生しました", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "エラーメッセージを表示", - "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "検索失敗", "xpack.csp.findings.findingsFlyout.calloutTitle": "一部のフィールドは{vendor}によって提供されていません", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "リソースID", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "リソース名", @@ -14733,10 +14737,6 @@ "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", "xpack.csp.kspmIntegration.vanillaOption.nameTitle": "自己管理", - "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "クラウドセキュリティ態勢", - "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "調査結果", - "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "ルール", - "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "Cloud Native Vulnerability Management", "xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "態勢評価中", "xpack.csp.noFindingsStates.indexing.indexingDescription": "データの収集とインデックス作成を待機しています。結果を表示するには、しばらくたってから確認してください", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "調査結果の収集に想定よりも時間がかかっています。{docs}。", @@ -18101,16 +18101,6 @@ "xpack.enterpriseSearch.nav.homeTitle": "ホーム", "xpack.enterpriseSearch.nav.searchApplication.contentTitle": "コンテンツ", "xpack.enterpriseSearch.nav.searchApplication.docsExplorerTitle": "ドキュメントエクスプローラー", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.connectorsConfigurationLabel": "構成", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerConfigurationLabel": "構成", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerSchedulingLabel": "スケジュール", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.documentsTitle": "ドキュメント", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.domainManagementLabel": "ドメインを管理", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.indexMappingsTitle": "インデックスマッピング", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.overviewTitle": "概要", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.pipelinesLabel": "パイプライン", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.schedulingTitle": "スケジュール", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.syncRulesLabel": "同期ルール", "xpack.enterpriseSearch.navigation.applicationsSearchApplicationsLinkLabel": "検索アプリケーション", "xpack.enterpriseSearch.navigation.appSearchEnginesLinkLabel": "エンジン", "xpack.enterpriseSearch.navigation.contentConnectorsLinkLabel": "コネクター", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index d6bca0a79d647..7d1c66306095b 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -7023,6 +7023,14 @@ "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "已配置告警阻止,但由于许可不足而无法应用", "securitySolutionPackages.alertSuppressionRuleForm.upsell": "告警阻止通过{requiredLicense}或更高级许可证启用", "securitySolutionPackages.beta.label": "公测版", + "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失败", + "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "不可用", + "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "通过", + "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "搜索失败", + "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "云安全态势", + "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "结果", + "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "规则", + "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "云原生漏洞管理", "securitySolutionPackages.dataTable.ariaLabel": "告警", "securitySolutionPackages.dataTable.columnHeaders.flyout.pane.removeColumnButtonLabel": "移除列", "securitySolutionPackages.dataTable.eventRenderedView.eventSummary.column": "事件摘要", @@ -7352,6 +7360,7 @@ "share.urlService.redirect.RedirectManager.missingParamLocator": "未指定定位器 ID。在 URL 中指定'l'搜索参数,其应为现有定位器 ID。", "share.urlService.redirect.RedirectManager.missingParamParams": "定位器参数未指定。在 URL 中指定'p'搜索参数,其应为定位器参数的 JSON 序列化对象。", "share.urlService.redirect.RedirectManager.missingParamVersion": "定位器参数版本未指定。在 URL 中指定'v'搜索参数,其应为生成定位器参数时 Kibana 的版本。", + "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "未知错误", "sharedUXPackages.buttonToolbar.buttons.addFromLibrary.libraryButtonLabel": "从库中添加", "sharedUXPackages.buttonToolbar.toolbar.errorToolbarText": "有 120 多个附加按钮。请考虑限制按钮数量。", "sharedUXPackages.card.noData.description": "使用 Elastic 代理以简单统一的方式从您的计算机中收集数据。", @@ -14194,7 +14203,6 @@ "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities": "漏洞", "xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount": "漏洞", "xpack.csp.common.component.multiSelectFilter.searchWord": "搜索", - "sharedPlatformPackages.csp.common.utils.helpers.unknownError": "未知错误", "xpack.csp.compactFormattedNumber.naTitle": "不可用", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} 个失败和 {passed} 个通过的结果", "xpack.csp.complianceScoreChart.counterButtonLink.failedFindingsTooltip": "失败的结果", @@ -14209,9 +14217,6 @@ "xpack.csp.createPackagePolicy.customAssetsTab.rulesViewLabel": "查看 CSP 规则", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityDashboardViewLabel": "查看 CNVM 仪表板", "xpack.csp.createPackagePolicy.customAssetsTab.vulnerabilityFindingsViewLabel": "查看漏洞结果", - "securitySolutionPackages.csp.cspEvaluationBadge.failLabel": "失败", - "securitySolutionPackages.csp.cspEvaluationBadge.naLabel": "不可用", - "securitySolutionPackages.csp.cspEvaluationBadge.passLabel": "通过", "xpack.csp.cspIntegration.gcpCloudCredentials.cloudFormationSupportedMessage": "当前集成版本不支持为自动化凭据启动 Cloud Shell。请升级到最新版本以启用为自动化凭据启动 Cloud Shell。", "xpack.csp.cspmIntegration.awsOption.benchmarkTitle": "CIS AWS", "xpack.csp.cspmIntegration.awsOption.nameTitle": "AWS", @@ -14295,7 +14300,6 @@ "xpack.csp.findings.distributionBar.totalPassedLabel": "通过的结果", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "检索搜索结果时遇到问题", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "显示错误消息", - "securitySolutionPackages.csp.findings.findingsErrorToast.searchFailedTitle": "搜索失败", "xpack.csp.findings.findingsFlyout.calloutTitle": "{vendor} 未提供某些字段", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceId": "资源 ID", "xpack.csp.findings.findingsFlyout.flyoutDescriptionList.resourceName": "资源名称", @@ -14465,10 +14469,6 @@ "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", "xpack.csp.kspmIntegration.vanillaOption.nameTitle": "自管型", - "securitySolutionPackages.csp.navigation.dashboardNavItemLabel": "云安全态势", - "securitySolutionPackages.csp.navigation.findingsNavItemLabel": "结果", - "securitySolutionPackages.csp.navigation.rulesNavItemLabel": "规则", - "securitySolutionPackages.csp.navigation.vulnerabilityDashboardNavItemLabel": "云原生漏洞管理", "xpack.csp.noFindingsStates.indexing.indexingButtonTitle": "正进行态势评估", "xpack.csp.noFindingsStates.indexing.indexingDescription": "正在等待要收集和索引的数据。请稍后返回检查以查看结果", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "收集结果所需的时间长于预期。{docs}。", @@ -17801,16 +17801,6 @@ "xpack.enterpriseSearch.nav.relevanceTitle": "相关性", "xpack.enterpriseSearch.nav.searchApplication.contentTitle": "内容", "xpack.enterpriseSearch.nav.searchApplication.docsExplorerTitle": "文档浏览器", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.connectorsConfigurationLabel": "配置", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerConfigurationLabel": "配置", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.crawlerSchedulingLabel": "正在计划", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.documentsTitle": "文档", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.domainManagementLabel": "管理域", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.indexMappingsTitle": "索引映射", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.overviewTitle": "概览", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.pipelinesLabel": "管道", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.schedulingTitle": "正在计划", - "xpack.enterpriseSearch.nav.searchIndicesTitle.nav.syncRulesLabel": "同步规则", "xpack.enterpriseSearch.navigation.applicationsSearchApplicationsLinkLabel": "搜索应用程序", "xpack.enterpriseSearch.navigation.appSearchEnginesLinkLabel": "引擎", "xpack.enterpriseSearch.navigation.contentConnectorsLinkLabel": "连接器", From 03bbccc91d5c05c12cf710e029607e2f798b5ef4 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 00:05:46 +0100 Subject: [PATCH 13/29] Update jest.config.js for enterprise search plugin --- x-pack/plugins/enterprise_search/public/jest.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/jest.config.js b/x-pack/plugins/enterprise_search/public/jest.config.js index bcb842bf3ce7a..421ade9d742d7 100644 --- a/x-pack/plugins/enterprise_search/public/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/jest.config.js @@ -10,7 +10,8 @@ module.exports = { rootDir: '../../../..', /** all nested directories have their own Jest config file */ testMatch: [ - '/x-pack/plugins/enterprise_search/public/applications/**/*.test.{js,mjs,ts,tsx}', + '/x-pack/plugins/enterprise_search/public/applications/*.test.{js,mjs,ts,tsx}', + '/x-pack/plugins/enterprise_search/public/applications/shared/**/*.test.{js,mjs,ts,tsx}', ], roots: ['/x-pack/plugins/enterprise_search/public'], collectCoverage: true, From ec3539a9231950d670386e5eaf5f7d8c5d7be004 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 10:57:49 +0100 Subject: [PATCH 14/29] remove unused dependency from plugin setu --- x-pack/plugins/search_indices/public/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/search_indices/public/types.ts b/x-pack/plugins/search_indices/public/types.ts index 209d937bb97d1..a0f35333cbd5a 100644 --- a/x-pack/plugins/search_indices/public/types.ts +++ b/x-pack/plugins/search_indices/public/types.ts @@ -45,7 +45,6 @@ export interface AppPluginSetupDependencies { share: SharePluginSetup; serverless?: ServerlessPluginSetup; usageCollection?: UsageCollectionSetup; - search; } export interface SearchIndicesAppPluginStartDependencies { From ff7dfbe854730bd1755cc7e5dc4540b5209ad7df Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 11:09:47 +0100 Subject: [PATCH 15/29] Add jest coverage ignore patterns for enterprise search components --- .../applications/enterprise_search_content/jest.config.js | 5 +++++ x-pack/plugins/enterprise_search/public/jest.config.js | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js index c99850777f483..4aed53999144f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js @@ -21,6 +21,11 @@ module.exports = { ], coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content', + coveragePathIgnorePatterns: [ + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', + ], 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/jest.config.js b/x-pack/plugins/enterprise_search/public/jest.config.js index 421ade9d742d7..fec5a831f2fee 100644 --- a/x-pack/plugins/enterprise_search/public/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/jest.config.js @@ -11,7 +11,6 @@ module.exports = { /** all nested directories have their own Jest config file */ testMatch: [ '/x-pack/plugins/enterprise_search/public/applications/*.test.{js,mjs,ts,tsx}', - '/x-pack/plugins/enterprise_search/public/applications/shared/**/*.test.{js,mjs,ts,tsx}', ], roots: ['/x-pack/plugins/enterprise_search/public'], collectCoverage: true, From 6593c037eb0ed293fda54ed2b71e197635f2c72e Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 11:20:25 +0100 Subject: [PATCH 16/29] Add jest config ignore patterns for enterprise search components --- .../applications/enterprise_search_content/jest.config.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js index 4aed53999144f..c8d6cd925de2c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js @@ -26,6 +26,11 @@ module.exports = { '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', ], + testPathIgnorePatterns: [ + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', + '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', + ], modulePathIgnorePatterns: [ '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress', '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress', From fd209878e52bf2cfba5276597f870a5dccb27f1b Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 13:05:00 +0100 Subject: [PATCH 17/29] Fix error on not used tests files --- .../new_index/method_api/method_api.test.tsx | 2 +- .../enterprise_search_content/jest.config.js | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_api/method_api.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_api/method_api.test.tsx index 031d3e8da3ecd..0c2554d62a1ec 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_api/method_api.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_api/method_api.test.tsx @@ -17,7 +17,7 @@ import { NewSearchIndexTemplate } from '../new_search_index_template'; import { MethodApi } from './method_api'; -describe('MethodApi', () => { +describe.skip('MethodApi', () => { beforeEach(() => { jest.clearAllMocks(); setMockValues({ status: Status.IDLE }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js index c8d6cd925de2c..a55b8bbc715f4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js @@ -21,21 +21,8 @@ module.exports = { ], coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content', - coveragePathIgnorePatterns: [ - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', - ], - testPathIgnorePatterns: [ - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', - ], modulePathIgnorePatterns: [ '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress', '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', ], }; From e3ad0becf9611528612df6ccbbb045408a91a4ae Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 13:05:00 +0100 Subject: [PATCH 18/29] Fix error on not used tests files --- .../enterprise_search_content/jest.config.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js index c8d6cd925de2c..a55b8bbc715f4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/jest.config.js @@ -21,21 +21,8 @@ module.exports = { ], coverageDirectory: '/target/kibana-coverage/jest/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content', - coveragePathIgnorePatterns: [ - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', - ], - testPathIgnorePatterns: [ - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', - ], modulePathIgnorePatterns: [ '/x-pack/plugins/enterprise_search/public/applications/app_search/cypress', '/x-pack/plugins/enterprise_search/public/applications/workplace_search/cypress', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices', - '/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index', ], }; From 355507736fdc283b1ef45d4d1f6369ef66ceff8b Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 17:48:32 +0100 Subject: [PATCH 19/29] Add chrome service mock for jest tests --- .../helpers/setup_environment.tsx | 3 ++ ...ta_streams_project_level_retention.test.ts | 1 + .../home/data_streams_tab.test.ts | 2 ++ .../client_integration/home/home.test.ts | 2 ++ .../home/indices_tab.test.tsx | 29 ++++++++++--------- .../__jest__/components/index_table.test.js | 9 +++++- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx index 535e0219bf823..9694b6c19dc50 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx @@ -21,6 +21,7 @@ import { applicationServiceMock, fatalErrorsServiceMock, httpServiceMock, + chromeServiceMock, } from '@kbn/core/public/mocks'; import { GlobalFlyout } from '@kbn/es-ui-shared-plugin/public'; @@ -70,6 +71,7 @@ const appDependencies = { executionContext: executionContextServiceMock.createStartContract(), http: httpServiceMock.createSetupContract(), application: applicationServiceMock.createStartContract(), + chrome: chromeServiceMock.createStartContract(), fatalErrors: fatalErrorsServiceMock.createSetupContract(), }, plugins: { @@ -105,6 +107,7 @@ const { Provider: KibanaReactContextProvider } = createKibanaReactContext({ uiSettings: uiSettingsServiceMock.createSetupContract(), settings: settingsServiceMock.createStartContract(), theme: themeServiceMock.createStartContract(), + chrome: chromeServiceMock.createStartContract(), kibanaVersion: { get: () => kibanaVersion, }, diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_project_level_retention.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_project_level_retention.test.ts index 19d6f169429b7..4f560b07b392e 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_project_level_retention.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_project_level_retention.test.ts @@ -37,6 +37,7 @@ const urlServiceMock = { }), }, }; +jest.mock('react-use/lib/useObservable', () => () => jest.fn()); describe('Data Streams - Project level max retention', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts index 3bc122ad867f6..cb6a9f8982ac7 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/data_streams_tab.test.ts @@ -26,6 +26,8 @@ import { createNonDataStreamIndex, } from './data_streams_tab.helpers'; +jest.mock('react-use/lib/useObservable', () => () => jest.fn()); + const nonBreakingSpace = ' '; const urlServiceMock = { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts index ef3bfabf7b9c9..e296069b5276b 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/home.test.ts @@ -10,6 +10,8 @@ import { act } from 'react-dom/test-utils'; import { setupEnvironment } from '../helpers'; import { HomeTestBed, setup } from './home.helpers'; +jest.mock('react-use/lib/useObservable', () => () => jest.fn()); + describe('', () => { const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); let testBed: HomeTestBed; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.tsx index a8256a2e00b27..733ed9c62793d 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.test.tsx @@ -8,22 +8,9 @@ /* * Mocking EuiSearchBar because its onChange is not firing during tests */ +import React from 'react'; import { EuiSearchBoxProps } from '@elastic/eui/src/components/search_bar/search_box'; - import { applicationServiceMock } from '@kbn/core/public/mocks'; -jest.mock('@elastic/eui/lib/components/search_bar/search_box', () => { - return { - EuiSearchBox: (props: EuiSearchBoxProps) => ( - ) => { - props.onSearch(event.target.value); - }} - /> - ), - }; -}); -import React from 'react'; import { act } from 'react-dom/test-utils'; import { API_BASE_PATH, Index, INTERNAL_API_BASE_PATH } from '../../../common'; @@ -41,6 +28,20 @@ import { IndexManagementBreadcrumb, } from '../../../public/application/services/breadcrumbs'; +jest.mock('@elastic/eui/lib/components/search_bar/search_box', () => { + return { + EuiSearchBox: (props: EuiSearchBoxProps) => ( + ) => { + props.onSearch(event.target.value); + }} + /> + ), + }; +}); +jest.mock('react-use/lib/useObservable', () => () => jest.fn()); + describe('', () => { let testBed: IndicesTestBed; let httpSetup: ReturnType['httpSetup']; diff --git a/x-pack/plugins/index_management/__jest__/components/index_table.test.js b/x-pack/plugins/index_management/__jest__/components/index_table.test.js index 0a59fef7be6e6..43ba97a970571 100644 --- a/x-pack/plugins/index_management/__jest__/components/index_table.test.js +++ b/x-pack/plugins/index_management/__jest__/components/index_table.test.js @@ -26,7 +26,11 @@ import { setExtensionsService } from '../../public/application/store/selectors/e import { ExtensionsService } from '../../public/services'; import { kibanaVersion } from '../client_integration/helpers'; -import { notificationServiceMock, executionContextServiceMock } from '@kbn/core/public/mocks'; +import { + notificationServiceMock, + executionContextServiceMock, + chromeServiceMock, +} from '@kbn/core/public/mocks'; let store = null; const indices = []; @@ -44,6 +48,8 @@ const getBaseFakeIndex = (isOpen) => { }; }; +jest.mock('react-use/lib/useObservable', () => () => jest.fn()); + for (let i = 0; i < 105; i++) { indices.push({ ...getBaseFakeIndex(true), @@ -159,6 +165,7 @@ describe('index table', () => { core: { getUrlForApp: () => {}, executionContext: executionContextServiceMock.createStartContract(), + chrome: chromeServiceMock.createStartContract(), }, plugins: {}, url: urlServiceMock, From 9ad5001e3e6e2518fb68f1e1fb19020194067a2a Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 17:53:45 +0100 Subject: [PATCH 20/29] Update search sidenav navigation and breadcrumbs --- .../tests/search_sidenav.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts index f90ea3e7b705f..743f1cad451e6 100644 --- a/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts +++ b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts @@ -50,14 +50,16 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // check the Content > Indices section await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + deepLinkId: 'management:index_management', }); await solutionNavigation.sidenav.expectLinkActive({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + deepLinkId: 'management:index_management', }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Deployment' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Stack Management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Index Management' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'enterpriseSearchContent:searchIndices', + text: 'Indices', }); // navigate to a different section From 1d6e3f75b7669ca25e0fcbcc14ca81e888c95e29 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Thu, 19 Dec 2024 23:50:34 +0100 Subject: [PATCH 21/29] fix(test): Update nav.test.tsx for enterprise search management --- .../public/applications/shared/layout/nav.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index 2e7359f630221..95e6870fa5859 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -41,9 +41,9 @@ const baseNavItems = [ items: [ { 'data-test-subj': 'searchSideNav-Indices', - href: '/app/elasticsearch/content/search_indices', + href: '/app/management/data/index_management/', id: 'search_indices', - items: [], + items: undefined, name: 'Indices', }, { @@ -148,9 +148,9 @@ const mockNavLinks = [ url: '/app/elasticsearch/overview', }, { - id: 'enterpriseSearchContent:searchIndices', + id: 'management:index_management', title: 'Indices', - url: '/app/elasticsearch/content/search_indices', + url: '/app/management/data/index_management/', }, { id: 'enterpriseSearchContent:connectors', From af6b879629b2215b6bd8d86d7ecc5a2b694f6c0d Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Fri, 27 Dec 2024 21:11:11 +0100 Subject: [PATCH 22/29] Remove empty file after merge --- .../components/search_index/indices/indices_nav.test.tsx | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx b/x-pack/solutions/search/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/indices/indices_nav.test.tsx deleted file mode 100644 index e69de29bb2d1d..0000000000000 From befb4b42fd0e479620ba5bcbe44d730252ce3e92 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Sun, 5 Jan 2025 21:55:06 +0100 Subject: [PATCH 23/29] Fix FTR common tests --- .../server/collectors/application_usage/schema.ts | 2 ++ x-pack/test/functional/page_objects/index_management_page.ts | 4 ++-- .../ui_capabilities/security_and_spaces/tests/catalogue.ts | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts index dd327dd4706d5..6197a9408b87a 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts @@ -138,6 +138,8 @@ export const applicationUsageSchema = { enterpriseSearchContent: commonSchema, searchInferenceEndpoints: commonSchema, searchPlayground: commonSchema, + elasticsearchIndices: commonSchema, + elasticsearchStart: commonSchema, enterpriseSearchAnalytics: commonSchema, enterpriseSearchApplications: commonSchema, enterpriseSearchAISearch: commonSchema, diff --git a/x-pack/test/functional/page_objects/index_management_page.ts b/x-pack/test/functional/page_objects/index_management_page.ts index 207bf2281c080..d66f35e5713d0 100644 --- a/x-pack/test/functional/page_objects/index_management_page.ts +++ b/x-pack/test/functional/page_objects/index_management_page.ts @@ -79,7 +79,7 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) const indexList = await testSubjects.findAll('indexTableIndexNameLink'); await indexList[indexOfRow].click(); await retry.waitFor('details page title to show up', async () => { - return (await testSubjects.isDisplayed('indexDetailsHeader')) === true; + return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; }); }, @@ -158,7 +158,7 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) const indexList = await testSubjects.findAll('indexTableIndexNameLink'); await indexList[indexOfRow].click(); await retry.waitFor('index details page title to show up', async () => { - return (await testSubjects.isDisplayed('indexDetailsHeader')) === true; + return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; }); }, async expectIndexDetailsPageIsLoaded() { diff --git a/x-pack/test/ui_capabilities/security_and_spaces/tests/catalogue.ts b/x-pack/test/ui_capabilities/security_and_spaces/tests/catalogue.ts index 71324846b2160..7b7d11eacbef6 100644 --- a/x-pack/test/ui_capabilities/security_and_spaces/tests/catalogue.ts +++ b/x-pack/test/ui_capabilities/security_and_spaces/tests/catalogue.ts @@ -88,6 +88,8 @@ export default function catalogueTests({ getService }: FtrProviderContext) { 'enterpriseSearchSemanticSearch', 'enterpriseSearchElasticsearch', 'searchPlayground', + 'elasticsearchIndices', + 'elasticsearchStart', 'searchInferenceEndpoints', 'appSearch', 'observabilityAIAssistant', From 735e3b55310bfb6ea71c0a03b0811f871ceaa1c2 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Sun, 5 Jan 2025 23:39:58 +0100 Subject: [PATCH 24/29] Fix telemetry check --- .../shared/telemetry/schema/oss_platform.json | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/src/platform/plugins/shared/telemetry/schema/oss_platform.json b/src/platform/plugins/shared/telemetry/schema/oss_platform.json index 2bd3174ba35d3..8f249135ea6cd 100644 --- a/src/platform/plugins/shared/telemetry/schema/oss_platform.json +++ b/src/platform/plugins/shared/telemetry/schema/oss_platform.json @@ -2360,6 +2360,268 @@ } } }, + "elasticsearchIndices": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "Always `main`" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } + }, + "views": { + "type": "array", + "items": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } + } + } + } + } + } + }, + "elasticsearchStart": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "Always `main`" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } + }, + "views": { + "type": "array", + "items": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } + } + } + } + } + } + }, "enterpriseSearchAnalytics": { "properties": { "appId": { From a6f3b8fc5029a0499a88c1349d0a472f7ea612df Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 6 Jan 2025 14:51:14 +0100 Subject: [PATCH 25/29] Fix indexManagement ftr tests --- .../accessibility/apps/group1/management.ts | 2 ++ .../index_management/index_details_page.ts | 6 ++-- .../remote_clusters_index_management_flow.ts | 4 +-- .../page_objects/index_management_page.ts | 5 +--- .../page_objects/search_index_detail.ts | 29 ++++++++++++------- .../index_management/index_detail.ts | 21 +++++++++----- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/x-pack/test/accessibility/apps/group1/management.ts b/x-pack/test/accessibility/apps/group1/management.ts index 0a11e649c29ac..11e27ca1655ea 100644 --- a/x-pack/test/accessibility/apps/group1/management.ts +++ b/x-pack/test/accessibility/apps/group1/management.ts @@ -14,6 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'header', 'indexPatternFieldEditorObjects', 'indexManagement', + 'searchIndexDetail', ]); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); @@ -52,6 +53,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('index details - overview', async () => { await PageObjects.settings.clickIndexManagement(); await PageObjects.indexManagement.clickIndexAt(0); + await PageObjects.searchIndexDetail.expectIndexDetailsPageIsLoaded(); await a11y.testAppSnapshot(); }); diff --git a/x-pack/test/functional/apps/index_management/index_details_page.ts b/x-pack/test/functional/apps/index_management/index_details_page.ts index 454210ef9ab76..587872a777507 100644 --- a/x-pack/test/functional/apps/index_management/index_details_page.ts +++ b/x-pack/test/functional/apps/index_management/index_details_page.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { - const pageObjects = getPageObjects(['common', 'indexManagement', 'header']); + const pageObjects = getPageObjects(['common', 'indexManagement', 'header', 'searchIndexDetail']); const log = getService('log'); const security = getService('security'); @@ -24,8 +24,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // display hidden indices to have some rows in the indices table await pageObjects.indexManagement.toggleHiddenIndices(); // click the first index in the table and wait for the index details page - await pageObjects.indexManagement.indexDetailsPage.openIndexDetailsPage(0); - await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsPageIsLoaded(); + await pageObjects.searchIndexDetail.openIndicesDetailFromIndexManagementIndicesListTable(0); + await pageObjects.searchIndexDetail.expectIndexDetailsPageIsLoaded(); }); }); }; diff --git a/x-pack/test/functional/apps/remote_clusters/ccs/remote_clusters_index_management_flow.ts b/x-pack/test/functional/apps/remote_clusters/ccs/remote_clusters_index_management_flow.ts index 4f710b3730353..5666fd540fe99 100644 --- a/x-pack/test/functional/apps/remote_clusters/ccs/remote_clusters_index_management_flow.ts +++ b/x-pack/test/functional/apps/remote_clusters/ccs/remote_clusters_index_management_flow.ts @@ -14,6 +14,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 'remoteClusters', 'indexManagement', 'crossClusterReplication', + 'searchIndexDetail', ]); const security = getService('security'); const retry = getService('retry'); @@ -88,8 +89,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('Verify that the follower index is duplicating from the remote.', async () => { await pageObjects.indexManagement.clickIndexAt(0); - await pageObjects.indexManagement.performIndexAction('flush'); - await testSubjects.click('indexDetailsBackToIndicesButton'); + await pageObjects.searchIndexDetail.expectIndexDetailsPageIsLoaded(); await pageObjects.common.navigateToApp('indexManagement'); await retry.waitForWithTimeout('indices table to be visible', 15000, async () => { return await testSubjects.isDisplayed('indicesList'); diff --git a/x-pack/test/functional/page_objects/index_management_page.ts b/x-pack/test/functional/page_objects/index_management_page.ts index aa95a2e5492d3..02c4d7a1d9ffa 100644 --- a/x-pack/test/functional/page_objects/index_management_page.ts +++ b/x-pack/test/functional/page_objects/index_management_page.ts @@ -82,9 +82,6 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) async clickIndexAt(indexOfRow: number): Promise { const indexList = await testSubjects.findAll('indexTableIndexNameLink'); await indexList[indexOfRow].click(); - await retry.waitFor('details page title to show up', async () => { - return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; - }); }, async performIndexAction(action: string) { @@ -162,7 +159,7 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) const indexList = await testSubjects.findAll('indexTableIndexNameLink'); await indexList[indexOfRow].click(); await retry.waitFor('index details page title to show up', async () => { - return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; + return (await testSubjects.isDisplayed('indexDetailsHeader')) === true; }); }, async expectIndexDetailsPageIsLoaded() { diff --git a/x-pack/test/functional/page_objects/search_index_detail.ts b/x-pack/test/functional/page_objects/search_index_detail.ts index 7440ee1c94c41..5a2c7d012fd8d 100644 --- a/x-pack/test/functional/page_objects/search_index_detail.ts +++ b/x-pack/test/functional/page_objects/search_index_detail.ts @@ -13,12 +13,26 @@ export function SearchIndexDetailProvider({ getService }: FtrProviderContext) { const browser = getService('browser'); const retry = getService('retry'); + const expectIndexDetailPageHeader = async function () { + await testSubjects.existOrFail('searchIndexDetailsHeader', { timeout: 2000 }); + }; + const expectSearchIndexDetailsTabsExists = async function () { + await testSubjects.existOrFail('dataTab'); + await testSubjects.existOrFail('mappingsTab'); + await testSubjects.existOrFail('settingsTab'); + }; + const expectAPIReferenceDocLinkExists = async function () { + await testSubjects.existOrFail('ApiReferenceDoc', { timeout: 2000 }); + }; + return { - async expectIndexDetailPageHeader() { - await testSubjects.existOrFail('searchIndexDetailsHeader', { timeout: 2000 }); - }, - async expectAPIReferenceDocLinkExists() { - await testSubjects.existOrFail('ApiReferenceDoc', { timeout: 2000 }); + expectIndexDetailPageHeader, + expectSearchIndexDetailsTabsExists, + expectAPIReferenceDocLinkExists, + async expectIndexDetailsPageIsLoaded() { + await expectIndexDetailPageHeader(); + await expectSearchIndexDetailsTabsExists(); + await expectAPIReferenceDocLinkExists(); }, async expectActionItemReplacedWhenHasDocs() { await testSubjects.missingOrFail('ApiReferenceDoc', { timeout: 2000 }); @@ -270,11 +284,6 @@ export function SearchIndexDetailProvider({ getService }: FtrProviderContext) { return (await testSubjects.isDisplayed('searchIndexDetailsHeader')) === true; }); }, - async expectSearchIndexDetailsTabsExists() { - await testSubjects.existOrFail('dataTab'); - await testSubjects.existOrFail('mappingsTab'); - await testSubjects.existOrFail('settingsTab'); - }, async expectBreadcrumbNavigationWithIndexName(indexName: string) { await testSubjects.existOrFail('euiBreadcrumb'); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts index 7330a5d162240..9846d0c97b701 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts @@ -9,7 +9,13 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { - const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); + const pageObjects = getPageObjects([ + 'svlCommonPage', + 'common', + 'indexManagement', + 'header', + 'searchIndexDetail', + ]); const browser = getService('browser'); const security = getService('security'); const testIndexName = `index-ftr-test-${Math.random()}`; @@ -36,17 +42,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('can view index details', function () { it('index with no documents', async () => { - await pageObjects.indexManagement.indexDetailsPage.openIndexDetailsPage(0); - await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsPageIsLoaded(); - await pageObjects.indexManagement.indexDetailsPage.expectTabsExists(); + await pageObjects.searchIndexDetail.openIndicesDetailFromIndexManagementIndicesListTable(0); + await pageObjects.searchIndexDetail.expectIndexDetailsPageIsLoaded(); }); it('can add mappings', async () => { - await pageObjects.indexManagement.indexDetailsPage.changeTab('indexDetailsTab-mappings'); - await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsMappingsAddFieldToBeEnabled(); + await pageObjects.searchIndexDetail.changeTab('mappingsTab'); + await pageObjects.searchIndexDetail.expectAddFieldToBeEnabled(); }); it('can edit settings', async () => { - await pageObjects.indexManagement.indexDetailsPage.changeTab('indexDetailsTab-settings'); - await pageObjects.indexManagement.indexDetailsPage.expectEditSettingsToBeEnabled(); + await pageObjects.searchIndexDetail.changeTab('settingsTab'); + await pageObjects.searchIndexDetail.expectEditSettingsToBeEnabled(); }); }); }); From 1df4762104165fd11c8c77e00a2186280d250059 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Mon, 6 Jan 2025 20:00:37 +0100 Subject: [PATCH 26/29] Skip management till other work will done --- .../index_management/index_details_page.ts | 2 +- .../page_objects/search_index_detail.ts | 8 +++---- .../index_management/index_detail.ts | 21 +++++++------------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/x-pack/test/functional/apps/index_management/index_details_page.ts b/x-pack/test/functional/apps/index_management/index_details_page.ts index 587872a777507..5151395574f74 100644 --- a/x-pack/test/functional/apps/index_management/index_details_page.ts +++ b/x-pack/test/functional/apps/index_management/index_details_page.ts @@ -18,7 +18,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToApp('indexManagement'); }); - it('Navigates to the index details page from the home page', async () => { + it.skip('Navigates to the index details page from the home page', async () => { await log.debug('Navigating to the index details page'); // display hidden indices to have some rows in the indices table diff --git a/x-pack/test/functional/page_objects/search_index_detail.ts b/x-pack/test/functional/page_objects/search_index_detail.ts index 5a2c7d012fd8d..83d420127beed 100644 --- a/x-pack/test/functional/page_objects/search_index_detail.ts +++ b/x-pack/test/functional/page_objects/search_index_detail.ts @@ -21,18 +21,16 @@ export function SearchIndexDetailProvider({ getService }: FtrProviderContext) { await testSubjects.existOrFail('mappingsTab'); await testSubjects.existOrFail('settingsTab'); }; - const expectAPIReferenceDocLinkExists = async function () { - await testSubjects.existOrFail('ApiReferenceDoc', { timeout: 2000 }); - }; return { expectIndexDetailPageHeader, expectSearchIndexDetailsTabsExists, - expectAPIReferenceDocLinkExists, + async expectAPIReferenceDocLinkExists() { + await testSubjects.existOrFail('ApiReferenceDoc', { timeout: 2000 }); + }, async expectIndexDetailsPageIsLoaded() { await expectIndexDetailPageHeader(); await expectSearchIndexDetailsTabsExists(); - await expectAPIReferenceDocLinkExists(); }, async expectActionItemReplacedWhenHasDocs() { await testSubjects.missingOrFail('ApiReferenceDoc', { timeout: 2000 }); diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts index 9846d0c97b701..7330a5d162240 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_detail.ts @@ -9,13 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { - const pageObjects = getPageObjects([ - 'svlCommonPage', - 'common', - 'indexManagement', - 'header', - 'searchIndexDetail', - ]); + const pageObjects = getPageObjects(['svlCommonPage', 'common', 'indexManagement', 'header']); const browser = getService('browser'); const security = getService('security'); const testIndexName = `index-ftr-test-${Math.random()}`; @@ -42,16 +36,17 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('can view index details', function () { it('index with no documents', async () => { - await pageObjects.searchIndexDetail.openIndicesDetailFromIndexManagementIndicesListTable(0); - await pageObjects.searchIndexDetail.expectIndexDetailsPageIsLoaded(); + await pageObjects.indexManagement.indexDetailsPage.openIndexDetailsPage(0); + await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsPageIsLoaded(); + await pageObjects.indexManagement.indexDetailsPage.expectTabsExists(); }); it('can add mappings', async () => { - await pageObjects.searchIndexDetail.changeTab('mappingsTab'); - await pageObjects.searchIndexDetail.expectAddFieldToBeEnabled(); + await pageObjects.indexManagement.indexDetailsPage.changeTab('indexDetailsTab-mappings'); + await pageObjects.indexManagement.indexDetailsPage.expectIndexDetailsMappingsAddFieldToBeEnabled(); }); it('can edit settings', async () => { - await pageObjects.searchIndexDetail.changeTab('settingsTab'); - await pageObjects.searchIndexDetail.expectEditSettingsToBeEnabled(); + await pageObjects.indexManagement.indexDetailsPage.changeTab('indexDetailsTab-settings'); + await pageObjects.indexManagement.indexDetailsPage.expectEditSettingsToBeEnabled(); }); }); }); From 1c028c815146ee2c9a7233dfa623a6515e6e5ccb Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 7 Jan 2025 10:31:58 +0100 Subject: [PATCH 27/29] fix(quick_stat): Replace spaces with underscores in generated ID --- .../search_indices/public/components/quick_stats/quick_stat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/solutions/search/plugins/search_indices/public/components/quick_stats/quick_stat.tsx b/x-pack/solutions/search/plugins/search_indices/public/components/quick_stats/quick_stat.tsx index 9df28ccec4bd6..9f2e3785b3681 100644 --- a/x-pack/solutions/search/plugins/search_indices/public/components/quick_stats/quick_stat.tsx +++ b/x-pack/solutions/search/plugins/search_indices/public/components/quick_stats/quick_stat.tsx @@ -54,7 +54,7 @@ export const QuickStat: React.FC = ({ const id = useGeneratedHtmlId({ prefix: 'formAccordion', - suffix: title, + suffix: title.replace(/\s/g, '_'), }); return ( From d293306b4daea4935cb2d6c348d53b97a2700a17 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 7 Jan 2025 13:23:46 +0100 Subject: [PATCH 28/29] fix: update management ftr tests --- x-pack/test/accessibility/apps/group1/management.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/x-pack/test/accessibility/apps/group1/management.ts b/x-pack/test/accessibility/apps/group1/management.ts index 11e27ca1655ea..0e9f4208e56af 100644 --- a/x-pack/test/accessibility/apps/group1/management.ts +++ b/x-pack/test/accessibility/apps/group1/management.ts @@ -58,23 +58,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('index details - settings', async () => { - await PageObjects.indexManagement.clickIndexDetailsTab('settings'); + await PageObjects.searchIndexDetail.changeTab('settingsTab'); await a11y.testAppSnapshot(); }); it('index details - edit settings', async () => { - await PageObjects.indexManagement.clickIndexDetailsTab('settings'); - await PageObjects.indexManagement.clickIndexDetailsEditSettingsSwitch(); + await PageObjects.searchIndexDetail.changeTab('settingsTab'); + await PageObjects.searchIndexDetail.clickIndexDetailsEditSettingsSwitch(); await a11y.testAppSnapshot(); }); it('index details - mappings', async () => { - await PageObjects.indexManagement.clickIndexDetailsTab('mappings'); - await a11y.testAppSnapshot(); - }); - - it('index details - stats', async () => { - await PageObjects.indexManagement.clickIndexDetailsTab('stats'); + await PageObjects.searchIndexDetail.changeTab('mappingsTab'); await a11y.testAppSnapshot(); }); }); From 7405c754b0a401daa3d96440339cfa5cfb5d01b0 Mon Sep 17 00:00:00 2001 From: Yan Savitski Date: Tue, 7 Jan 2025 15:50:02 +0100 Subject: [PATCH 29/29] fix: check type --- x-pack/test/accessibility/apps/group1/management.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/accessibility/apps/group1/management.ts b/x-pack/test/accessibility/apps/group1/management.ts index 0e9f4208e56af..17f056159b278 100644 --- a/x-pack/test/accessibility/apps/group1/management.ts +++ b/x-pack/test/accessibility/apps/group1/management.ts @@ -64,7 +64,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('index details - edit settings', async () => { await PageObjects.searchIndexDetail.changeTab('settingsTab'); - await PageObjects.searchIndexDetail.clickIndexDetailsEditSettingsSwitch(); + await PageObjects.indexManagement.clickIndexDetailsEditSettingsSwitch(); await a11y.testAppSnapshot(); });