diff --git a/x-pack/packages/index-management/index_management_shared_types/src/types.ts b/x-pack/packages/index-management/index_management_shared_types/src/types.ts index 1413830f2931fa..82dba5ed7e3102 100644 --- a/x-pack/packages/index-management/index_management_shared_types/src/types.ts +++ b/x-pack/packages/index-management/index_management_shared_types/src/types.ts @@ -25,6 +25,9 @@ export interface IndexManagementPluginStart { getIndexMappingComponent: (deps: { history: ScopedHistory; }) => React.FC; + getIndexSettingsComponent: (deps: { + history: ScopedHistory; + }) => React.FC; } export interface Index { @@ -56,7 +59,9 @@ export interface IndexMappingProps { index?: Index; showAboutMappings?: boolean; } - +export interface IndexSettingProps { + indexName: string; +} export interface SendRequestResponse { data: D | null; error: E | null; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context.tsx similarity index 78% rename from x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context.tsx rename to x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context.tsx index 7aa0f07e8e4928..a341b0fb678133 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context.tsx @@ -6,14 +6,14 @@ */ import React from 'react'; -import { documentationService } from '../../../../services'; -import { UIM_APP_NAME } from '../../../../../../common/constants/ui_metric'; -import { httpService } from '../../../../services/http'; -import { notificationService } from '../../../../services/notification'; -import { UiMetricService } from '../../../../services/ui_metric'; -import { AppDependencies, IndexManagementAppContext } from '../../../..'; +import { documentationService } from '../../../../../services'; +import { UIM_APP_NAME } from '../../../../../../../common/constants/ui_metric'; +import { httpService } from '../../../../../services/http'; +import { notificationService } from '../../../../../services/notification'; +import { UiMetricService } from '../../../../../services/ui_metric'; +import { AppDependencies, IndexManagementAppContext } from '../../../../..'; import { IndexMappingWithContextProps } from './index_mapping_with_context_types'; -import { DetailsPageMappings } from './details_page_mappings'; +import { DetailsPageMappings } from '../details_page_mappings'; export const IndexMappingWithContext: React.FC = ({ core, diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context_types.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context_types.tsx similarity index 82% rename from x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context_types.tsx rename to x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context_types.tsx index 228f928f1ec74a..86d16fc35e65b4 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mapping_with_context_types.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mapping_with_context_types.tsx @@ -7,8 +7,8 @@ import { CoreStart } from '@kbn/core/public'; import { IndexMappingProps } from '@kbn/index-management-shared-types'; -import { AppDependencies } from '../../../../app_context'; -import { ExtensionsService } from '../../../../../services/extensions_service'; +import { AppDependencies } from '../../../../../app_context'; +import { ExtensionsService } from '../../../../../../services/extensions_service'; export type IndexMappingWithContextProps = { core: CoreStart; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mappings_embeddable.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mappings_embeddable.tsx similarity index 100% rename from x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/index_mappings_embeddable.tsx rename to x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_mappings_embeddable.tsx diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_embeddable.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_embeddable.tsx new file mode 100644 index 00000000000000..70e738dbd5bd70 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_embeddable.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiLoadingSpinner } from '@elastic/eui'; +import { dynamic } from '@kbn/shared-ux-utility'; +import React, { Suspense, ComponentType } from 'react'; +import { IndexSettingWithContextProps } from './index_settings_with_context_types'; + +const IndexSettingsWithContext = dynamic>(() => + import('./index_settings_with_context').then((mod) => ({ default: mod.IndexSettingsWithContext })) +); + +export const IndexSettings: React.FC = (props) => { + return ( + }> + + + ); +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context.tsx new file mode 100644 index 00000000000000..d56c2c46e8ec49 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { documentationService } from '../../../../../services'; +import { UIM_APP_NAME } from '../../../../../../../common/constants/ui_metric'; +import { httpService } from '../../../../../services/http'; +import { notificationService } from '../../../../../services/notification'; +import { UiMetricService } from '../../../../../services/ui_metric'; +import { AppDependencies, IndexManagementAppContext } from '../../../../..'; +import { DetailsPageSettings } from '../details_page_settings'; +import { IndexSettingWithContextProps } from './index_settings_with_context_types'; +import { setUiMetricService } from '../../../../../services/api'; + +export const IndexSettingsWithContext: React.FC = ({ + core, + dependencies, + indexName, + usageCollection, +}) => { + // this normally happens when the index management app is rendered + // but if components are embedded elsewhere that setup is skipped, so we have to do it here + // would do it in plugin.ts but that blows up the bundle size + // can't do it in an effect because then the first http call fails as the instantiation happens after first render + if (!httpService.httpClient) { + httpService.setup(core.http); + notificationService.setup(core.notifications); + } + documentationService.setup(core.docLinks); + + const uiMetricService = new UiMetricService(UIM_APP_NAME); + setUiMetricService(uiMetricService); + uiMetricService.setup(usageCollection); + + const newDependencies: AppDependencies = { + ...dependencies, + services: { + ...(dependencies.services || {}), + httpService, + notificationService, + uiMetricService, + }, + }; + return ( + + + + ); +}; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context_types.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context_types.tsx new file mode 100644 index 00000000000000..39600edcc13068 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/with_context_components/index_settings_with_context_types.tsx @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart } from '@kbn/core/public'; +import type { IndexSettingProps } from '@kbn/index-management-shared-types'; +import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; +import { AppDependencies } from '../../../../../app_context'; +import { ExtensionsService } from '../../../../../../services/extensions_service'; + +export type IndexSettingWithContextProps = { + core: CoreStart; + // omitting services here to constitute them inside the component + // this helps reduce bundle size significantly + dependencies: Omit & { + services: { extensionsService: ExtensionsService }; + }; + usageCollection: UsageCollectionSetup; +} & IndexSettingProps; diff --git a/x-pack/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts index 4efe613fc2a045..5b1706fe807bd4 100644 --- a/x-pack/plugins/index_management/public/plugin.ts +++ b/x-pack/plugins/index_management/public/plugin.ts @@ -26,8 +26,9 @@ import { ClientConfigType, SetupDependencies, StartDependencies } from './types' // avoid import from index files in plugin.ts, use specific import paths import { PLUGIN } from '../common/constants/plugin'; -import { IndexMapping } from './application/sections/home/index_list/details_page/index_mappings_embeddable'; +import { IndexMapping } from './application/sections/home/index_list/details_page/with_context_components/index_mappings_embeddable'; import { PublicApiService } from './services/public_api_service'; +import { IndexSettings } from './application/sections/home/index_list/details_page/with_context_components/index_settings_embeddable'; export class IndexMgmtUIPlugin implements @@ -159,6 +160,44 @@ export class IndexMgmtUIPlugin return IndexMapping({ dependencies: appDependencies, core: coreStart, ...props }); }; }, + getIndexSettingsComponent: (deps: { history: ScopedHistory }) => { + const { docLinks, fatalErrors, application, uiSettings, executionContext, settings, http } = + coreStart; + const { url } = share; + const appDependencies = { + core: { + fatalErrors, + getUrlForApp: application.getUrlForApp, + executionContext, + application, + http, + }, + plugins: { + usageCollection, + isFleetEnabled: Boolean(fleet), + share, + cloud, + console, + ml, + licensing, + }, + services: { + extensionsService: this.extensionsService, + }, + config: this.config, + history: deps.history, + setBreadcrumbs: undefined as any, // breadcrumbService.setBreadcrumbs, + uiSettings, + settings, + url, + docLinks, + kibanaVersion: this.kibanaVersion, + theme$: coreStart.theme.theme$, + }; + return (props: any) => { + return IndexSettings({ dependencies: appDependencies, core: coreStart, ...props }); + }; + }, }; } public stop() {} 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 bca02f1ef12644..46e595a3d22075 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 @@ -34,8 +34,9 @@ import { useIndexMapping } from '../../hooks/api/use_index_mappings'; import { IndexDocuments } from '../index_documents/index_documents'; import { DeleteIndexModal } from './delete_index_modal'; import { IndexloadingError } from './details_page_loading_error'; -import { SearchIndicesDetailsMappingsTabs } from '../../routes'; +import { SearchIndexDetailsTabs } from '../../routes'; import { SearchIndexDetailsMappings } from './details_page_mappings'; +import { SearchIndexDetailsSettings } from './details_page_settings'; export const SearchIndexDetailsPage = () => { const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName); @@ -49,33 +50,40 @@ export const SearchIndexDetailsPage = () => { isInitialLoading: isMappingsInitialLoading, } = useIndexMapping(indexName); - const SearchIndexDetailsTabs: EuiTabbedContentTab[] = useMemo(() => { + const detailsPageTabs: EuiTabbedContentTab[] = useMemo(() => { return [ { - id: SearchIndicesDetailsMappingsTabs.DATA, + id: SearchIndexDetailsTabs.DATA, name: i18n.translate('xpack.searchIndices.documentsTabLabel', { defaultMessage: 'Data', }), content: , - 'data-test-subj': `${SearchIndicesDetailsMappingsTabs.DATA}Tab`, + 'data-test-subj': `${SearchIndexDetailsTabs.DATA}Tab`, }, { - id: SearchIndicesDetailsMappingsTabs.MAPPINGS, + id: SearchIndexDetailsTabs.MAPPINGS, name: i18n.translate('xpack.searchIndices.mappingsTabLabel', { defaultMessage: 'Mappings', }), content: , - 'data-test-subj': `${SearchIndicesDetailsMappingsTabs.MAPPINGS}Tab`, + 'data-test-subj': `${SearchIndexDetailsTabs.MAPPINGS}Tab`, + }, + { + id: SearchIndexDetailsTabs.SETTINGS, + name: i18n.translate('xpack.searchIndices.settingsTabLabel', { + defaultMessage: 'Settings', + }), + content: , + 'data-test-subj': `${SearchIndexDetailsTabs.SETTINGS}Tab`, }, ]; }, [index, indexName]); - - const [selectedTab, setSelectedTab] = useState(SearchIndexDetailsTabs[0]); + const [selectedTab, setSelectedTab] = useState(detailsPageTabs[0]); useEffect(() => { - const newTab = SearchIndexDetailsTabs.find((tab) => tab.id === tabId); + const newTab = detailsPageTabs.find((tab) => tab.id === tabId); if (newTab) setSelectedTab(newTab); - }, [SearchIndexDetailsTabs, tabId]); + }, [detailsPageTabs, tabId]); const handleTabClick = useCallback( (tab) => { @@ -215,7 +223,7 @@ export const SearchIndexDetailsPage = () => { diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page_settings.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page_settings.tsx new file mode 100644 index 00000000000000..d70591c065b133 --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/indices/details_page_settings.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { useMemo } from 'react'; +import { useKibana } from '../../hooks/use_kibana'; + +interface SearchIndexDetailsSettingsProps { + indexName: string; +} +export const SearchIndexDetailsSettings = ({ indexName }: SearchIndexDetailsSettingsProps) => { + const { indexManagement, history } = useKibana().services; + + const IndexSettingsComponent = useMemo( + () => indexManagement.getIndexSettingsComponent({ history }), + [indexManagement, history] + ); + + return ; +}; diff --git a/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx b/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx index 73aec33f80b5cf..f6c931d73a99e5 100644 --- a/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx @@ -9,7 +9,7 @@ import { Route, Router, Routes } from '@kbn/shared-ux-router'; import { Redirect } from 'react-router-dom'; import { useKibana } from '../../hooks/use_kibana'; import { - SearchIndicesDetailsMappingsTabs, + SearchIndexDetailsTabs, SEARCH_INDICES_DETAILS_PATH, SEARCH_INDICES_DETAILS_TABS_PATH, } from '../../routes'; @@ -25,7 +25,7 @@ export const SearchIndicesRouter: React.FC = () => { diff --git a/x-pack/plugins/search_indices/public/routes.ts b/x-pack/plugins/search_indices/public/routes.ts index 3e347881d12196..9afa0463855768 100644 --- a/x-pack/plugins/search_indices/public/routes.ts +++ b/x-pack/plugins/search_indices/public/routes.ts @@ -8,7 +8,8 @@ export const ROOT_PATH = '/'; export const SEARCH_INDICES_DETAILS_PATH = `${ROOT_PATH}index_details/:indexName`; export const SEARCH_INDICES_DETAILS_TABS_PATH = `${SEARCH_INDICES_DETAILS_PATH}/:tabId`; -export enum SearchIndicesDetailsMappingsTabs { +export enum SearchIndexDetailsTabs { DATA = 'data', MAPPINGS = 'mappings', + SETTINGS = 'settings', } diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts index 8ffbfd2bcb8c1e..f19a713eece5b4 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_search_index_detail_page.ts @@ -115,11 +115,17 @@ export function SvlSearchIndexDetailPageProvider({ getService }: FtrProviderCont async expectShouldDefaultToDataTab() { expect(await browser.getCurrentUrl()).contain('/data'); }, - async withDataChangeTabs(tab: 'dataTab' | 'mappingsTab') { + async withDataChangeTabs(tab: 'dataTab' | 'mappingsTab' | 'settingsTab') { await testSubjects.click(tab); }, - async expectUrlShouldChangeTo(tab: 'data' | 'mappings') { + 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 }); + }, }; } diff --git a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts index 7f40ec9127c6c5..a4d58d32c751b3 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts @@ -91,9 +91,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchIndexDetailPage.expectWithDataTabsExists(); await pageObjects.svlSearchIndexDetailPage.expectShouldDefaultToDataTab(); }); - it('should be able to change tabs', async () => { + it('should be able to change tabs to mappings and mappings is shown', async () => { await pageObjects.svlSearchIndexDetailPage.withDataChangeTabs('mappingsTab'); await pageObjects.svlSearchIndexDetailPage.expectUrlShouldChangeTo('mappings'); + await pageObjects.svlSearchIndexDetailPage.expectMappingsComponentIsVisible(); + }); + it('should be able to change tabs to settings and settings is shown', async () => { + await pageObjects.svlSearchIndexDetailPage.withDataChangeTabs('settingsTab'); + await pageObjects.svlSearchIndexDetailPage.expectUrlShouldChangeTo('settings'); + await pageObjects.svlSearchIndexDetailPage.expectSettingsComponentIsVisible(); }); });