From 0c222addbb417e0a1f08091108d5eba24f543764 Mon Sep 17 00:00:00 2001
From: Saarika Bhasi <55930906+saarikabhasi@users.noreply.github.com>
Date: Thu, 19 Sep 2024 12:50:19 -0400
Subject: [PATCH] [Onboarding] Add mappings component to index details page
(#193314)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary
This PR adds mappings component to index detail page.
### Checklist
Delete any items that are not applicable to this PR.
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
---
x-pack/plugins/search_indices/kibana.jsonc | 1 +
.../search_indices/public/application.tsx | 5 +-
.../components/indices/details_page.tsx | 57 +++++++++++++++----
.../indices/details_page_mappings.tsx | 30 ++++++++++
.../components/indices/indices_router.tsx | 33 ++++++++---
.../plugins/search_indices/public/routes.ts | 5 ++
x-pack/plugins/search_indices/public/types.ts | 2 +
.../svl_search_index_detail_page.ts | 16 +++++-
.../test_suites/search/search_index_detail.ts | 35 ++++++++----
9 files changed, 144 insertions(+), 40 deletions(-)
create mode 100644 x-pack/plugins/search_indices/public/components/indices/details_page_mappings.tsx
diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc
index 303a264d2bafd..63fbf63609dff 100644
--- a/x-pack/plugins/search_indices/kibana.jsonc
+++ b/x-pack/plugins/search_indices/kibana.jsonc
@@ -12,6 +12,7 @@
],
"requiredPlugins": [
"share",
+ "indexManagement",
],
"optionalPlugins": [
"cloud",
diff --git a/x-pack/plugins/search_indices/public/application.tsx b/x-pack/plugins/search_indices/public/application.tsx
index 62c4edb42d02c..c196020319589 100644
--- a/x-pack/plugins/search_indices/public/application.tsx
+++ b/x-pack/plugins/search_indices/public/application.tsx
@@ -13,7 +13,6 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { I18nProvider } from '@kbn/i18n-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { Router } from '@kbn/shared-ux-router';
import { UsageTrackerContextProvider } from './contexts/usage_tracker_context';
import { SearchIndicesServicesContextDeps } from './types';
@@ -30,9 +29,7 @@ export const renderApp = async (
-
-
-
+
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 ed498a777d712..bca02f1ef1264 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
@@ -10,7 +10,6 @@ import {
EuiButton,
EuiPageTemplate,
EuiFlexItem,
- EuiTabbedContent,
EuiFlexGroup,
EuiPopover,
EuiButtonIcon,
@@ -19,8 +18,10 @@ import {
EuiText,
EuiIcon,
EuiButtonEmpty,
+ EuiTabbedContent,
+ EuiTabbedContentTab,
} from '@elastic/eui';
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
@@ -33,11 +34,14 @@ 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 { SearchIndexDetailsMappings } from './details_page_mappings';
export const SearchIndexDetailsPage = () => {
const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName);
- const { console: consolePlugin, docLinks, application } = useKibana().services;
+ const tabId = decodeURIComponent(useParams<{ tabId: string }>().tabId);
+ const { console: consolePlugin, docLinks, application, history } = useKibana().services;
const { data: index, refetch, isError: isIndexError, isInitialLoading } = useIndex(indexName);
const {
data: mappings,
@@ -45,6 +49,41 @@ export const SearchIndexDetailsPage = () => {
isInitialLoading: isMappingsInitialLoading,
} = useIndexMapping(indexName);
+ const SearchIndexDetailsTabs: EuiTabbedContentTab[] = useMemo(() => {
+ return [
+ {
+ id: SearchIndicesDetailsMappingsTabs.DATA,
+ name: i18n.translate('xpack.searchIndices.documentsTabLabel', {
+ defaultMessage: 'Data',
+ }),
+ content: ,
+ 'data-test-subj': `${SearchIndicesDetailsMappingsTabs.DATA}Tab`,
+ },
+ {
+ id: SearchIndicesDetailsMappingsTabs.MAPPINGS,
+ name: i18n.translate('xpack.searchIndices.mappingsTabLabel', {
+ defaultMessage: 'Mappings',
+ }),
+ content: ,
+ 'data-test-subj': `${SearchIndicesDetailsMappingsTabs.MAPPINGS}Tab`,
+ },
+ ];
+ }, [index, indexName]);
+
+ const [selectedTab, setSelectedTab] = useState(SearchIndexDetailsTabs[0]);
+
+ useEffect(() => {
+ const newTab = SearchIndexDetailsTabs.find((tab) => tab.id === tabId);
+ if (newTab) setSelectedTab(newTab);
+ }, [SearchIndexDetailsTabs, tabId]);
+
+ const handleTabClick = useCallback(
+ (tab) => {
+ history.push(`index_details/${indexName}/${tab.id}`);
+ },
+
+ [history, indexName]
+ );
const embeddableConsole = useMemo(
() => (consolePlugin?.EmbeddableConsole ? : null),
[consolePlugin]
@@ -176,15 +215,9 @@ export const SearchIndexDetailsPage = () => {
,
- },
- ]}
+ tabs={SearchIndexDetailsTabs}
+ onTabClick={handleTabClick}
+ selectedTab={selectedTab}
/>
diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page_mappings.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page_mappings.tsx
new file mode 100644
index 0000000000000..c90d5cad94c83
--- /dev/null
+++ b/x-pack/plugins/search_indices/public/components/indices/details_page_mappings.tsx
@@ -0,0 +1,30 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiSpacer } from '@elastic/eui';
+import { Index } from '@kbn/index-management-shared-types';
+import React from 'react';
+import { useMemo } from 'react';
+import { useKibana } from '../../hooks/use_kibana';
+export interface SearchIndexDetailsMappingsProps {
+ index?: Index;
+}
+export const SearchIndexDetailsMappings = ({ index }: SearchIndexDetailsMappingsProps) => {
+ const { indexManagement, history } = useKibana().services;
+
+ const IndexMappingComponent = useMemo(
+ () => indexManagement.getIndexMappingComponent({ 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 fda9a9344f658..73aec33f80b5c 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
@@ -5,17 +5,32 @@
* 2.0.
*/
import React from 'react';
-import { Route, Routes } from '@kbn/shared-ux-router';
-import { SEARCH_INDICES_DETAILS_PATH } from '../../routes';
-import { SearchIndexDetailsPage } from './details_page';
+import { Route, Router, Routes } from '@kbn/shared-ux-router';
+import { Redirect } from 'react-router-dom';
import { useKibana } from '../../hooks/use_kibana';
-
+import {
+ SearchIndicesDetailsMappingsTabs,
+ SEARCH_INDICES_DETAILS_PATH,
+ SEARCH_INDICES_DETAILS_TABS_PATH,
+} from '../../routes';
+import { SearchIndexDetailsPage } from './details_page';
export const SearchIndicesRouter: React.FC = () => {
- const { application } = useKibana().services;
+ const { application, history } = useKibana().services;
return (
-
-
- application.navigateToApp('elasticsearchStart')} />
-
+
+
+
+
+
+
+
+
+ application.navigateToApp('elasticsearchStart')} />
+
+
);
};
diff --git a/x-pack/plugins/search_indices/public/routes.ts b/x-pack/plugins/search_indices/public/routes.ts
index 9687b11ad1692..3e347881d1219 100644
--- a/x-pack/plugins/search_indices/public/routes.ts
+++ b/x-pack/plugins/search_indices/public/routes.ts
@@ -7,3 +7,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 {
+ DATA = 'data',
+ MAPPINGS = 'mappings',
+}
diff --git a/x-pack/plugins/search_indices/public/types.ts b/x-pack/plugins/search_indices/public/types.ts
index 6e0192e34f87c..0f68863fe72f8 100644
--- a/x-pack/plugins/search_indices/public/types.ts
+++ b/x-pack/plugins/search_indices/public/types.ts
@@ -12,6 +12,7 @@ import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'
import type { SharePluginStart } from '@kbn/share-plugin/public';
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
import type { MappingPropertyBase } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
+import { IndexManagementPluginStart } from '@kbn/index-management-shared-types';
export interface SearchIndicesPluginSetup {
enabled: boolean;
@@ -37,6 +38,7 @@ export interface SearchIndicesServicesContextDeps {
export type SearchIndicesServicesContext = CoreStart &
SearchIndicesAppPluginStartDependencies & {
history: AppMountParameters['history'];
+ indexManagement: IndexManagementPluginStart;
};
export interface AppUsageTracker {
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 4c5a53a9a30e5..8ffbfd2bcb8c1 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
@@ -14,9 +14,6 @@ export function SvlSearchIndexDetailPageProvider({ getService }: FtrProviderCont
const retry = getService('retry');
return {
- async expectToBeIndexDetailPage() {
- expect(await browser.getCurrentUrl()).contain('/index_details');
- },
async expectIndexDetailPageHeader() {
await testSubjects.existOrFail('searchIndexDetailsHeader', { timeout: 2000 });
},
@@ -111,5 +108,18 @@ export function SvlSearchIndexDetailPageProvider({ getService }: FtrProviderCont
await testSubjects.click('reloadButton', 2000);
});
},
+ async expectWithDataTabsExists() {
+ await testSubjects.existOrFail('mappingsTab', { timeout: 2000 });
+ await testSubjects.existOrFail('dataTab', { timeout: 2000 });
+ },
+ async expectShouldDefaultToDataTab() {
+ expect(await browser.getCurrentUrl()).contain('/data');
+ },
+ async withDataChangeTabs(tab: 'dataTab' | 'mappingsTab') {
+ await testSubjects.click(tab);
+ },
+ async expectUrlShouldChangeTo(tab: 'data' | 'mappings') {
+ expect(await browser.getCurrentUrl()).contain(`/${tab}`);
+ },
};
}
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 da707ca55ac8b..7f40ec9127c6c 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
@@ -68,23 +68,34 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await pageObjects.svlSearchIndexDetailPage.expectAddDocumentCodeExamples();
});
- it('should have index documents', async () => {
- await es.index({
- index: indexName,
- body: {
- my_field: [1, 0, 1],
- },
- });
-
- await svlSearchNavigation.navigateToIndexDetailPage(indexName);
- await pageObjects.svlSearchIndexDetailPage.expectHasIndexDocuments();
- });
-
it('back to indices button should redirect to list page', async () => {
await pageObjects.svlSearchIndexDetailPage.expectBackToIndicesButtonExists();
await pageObjects.svlSearchIndexDetailPage.clickBackToIndicesButton();
await pageObjects.svlSearchIndexDetailPage.expectBackToIndicesButtonRedirectsToListPage();
});
+ describe('With data', () => {
+ before(async () => {
+ await svlSearchNavigation.navigateToIndexDetailPage(indexName);
+ await es.index({
+ index: indexName,
+ body: {
+ my_field: [1, 0, 1],
+ },
+ });
+ });
+ it('should have index documents', async () => {
+ await svlSearchNavigation.navigateToIndexDetailPage(indexName);
+ await pageObjects.svlSearchIndexDetailPage.expectHasIndexDocuments();
+ });
+ it('should have with data tabs', async () => {
+ await pageObjects.svlSearchIndexDetailPage.expectWithDataTabsExists();
+ await pageObjects.svlSearchIndexDetailPage.expectShouldDefaultToDataTab();
+ });
+ it('should be able to change tabs', async () => {
+ await pageObjects.svlSearchIndexDetailPage.withDataChangeTabs('mappingsTab');
+ await pageObjects.svlSearchIndexDetailPage.expectUrlShouldChangeTo('mappings');
+ });
+ });
describe('page loading error', () => {
before(async () => {