From 24d6dbcde633a0cd72228b719a5e084b2020a1b4 Mon Sep 17 00:00:00 2001 From: Yulia Cech Date: Tue, 9 Jan 2024 14:05:22 +0100 Subject: [PATCH 1/6] [Index Management] Fix navigation bug for the indices list --- .../index_list/details_page/details_page.tsx | 1 + .../details_page/details_page_content.tsx | 20 +++++++++----- .../index_actions_context_menu.js | 17 +++++++++--- .../index_list/index_table/index_table.js | 17 ++++++++++-- .../public/application/services/routing.ts | 26 ++++++++++++++----- 5 files changed, 62 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx index f028dee3d8eee..570b42e4cedfa 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx @@ -95,6 +95,7 @@ export const DetailsPage: FunctionComponent< tab={tab} fetchIndexDetails={fetchIndexDetails} history={history} + search={search} /> ); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx index adeadee6132c0..7c03dcb0bc186 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx @@ -17,6 +17,7 @@ import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import { RouteComponentProps } from 'react-router-dom'; +import qs from 'query-string'; import { renderBadges } from '../../../../lib/render_badges'; import { Index } from '../../../../../../common'; import { @@ -24,9 +25,8 @@ import { IndexDetailsSection, IndexDetailsTab, IndexDetailsTabId, - Section, } from '../../../../../../common/constants'; -import { getIndexDetailsLink } from '../../../../services/routing'; +import { getIndexDetailsLink, getIndexListUri } from '../../../../services/routing'; import { useAppContext } from '../../../../app_context'; import { DiscoverLink } from '../../../../lib/discover_link'; import { ManageIndexButton } from './manage_index_button'; @@ -78,12 +78,14 @@ interface Props { index: Index; tab: IndexDetailsTabId; history: RouteComponentProps['history']; + search: string; fetchIndexDetails: () => Promise; } export const DetailsPageContent: FunctionComponent = ({ index, tab, history, + search, fetchIndexDetails, }) => { const { @@ -108,16 +110,22 @@ export const DetailsPageContent: FunctionComponent = ({ return sortedTabs; }, [enableIndexStats, extensionsService.indexDetailsTabs, index]); + const { filter: filterParam, includeHiddenIndices: includeHiddenParam } = qs.parse(search); + const filter = String(filterParam); + const includeHiddenIndices = Boolean(includeHiddenParam); + const onSectionChange = useCallback( (newSection: IndexDetailsTabId) => { - return history.push(getIndexDetailsLink(index.name, newSection)); + return history.push( + getIndexDetailsLink(index.name, { filter, includeHiddenIndices }, newSection) + ); }, - [history, index] + [history, index.name, filter, includeHiddenIndices] ); const navigateToAllIndices = useCallback(() => { - history.push(`/${Section.Indices}`); - }, [history]); + history.push(getIndexListUri(filter, includeHiddenIndices)); + }, [history, filter, includeHiddenIndices]); const headerTabs = useMemo(() => { return tabs.map((tabConfig) => ({ diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js index 2faf623ce49fb..b96adabc2b05e 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js @@ -68,6 +68,7 @@ export class IndexActionsContextMenu extends Component { indices, reloadIndices, unfreezeIndices, + indicesListParams, } = this.props; const allOpen = every(indexNames, (indexName) => { return indexStatusByName[indexName] === INDEX_OPEN; @@ -82,7 +83,9 @@ export class IndexActionsContextMenu extends Component { defaultMessage: 'Show index overview', }), onClick: () => { - history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Overview)); + history.push( + getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Overview) + ); }, }); items.push({ @@ -91,7 +94,9 @@ export class IndexActionsContextMenu extends Component { defaultMessage: 'Show index settings', }), onClick: () => { - history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Settings)); + history.push( + getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Settings) + ); }, }); items.push({ @@ -100,7 +105,9 @@ export class IndexActionsContextMenu extends Component { defaultMessage: 'Show index mapping', }), onClick: () => { - history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Mappings)); + history.push( + getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Mappings) + ); }, }); if (allOpen && enableIndexActions) { @@ -110,7 +117,9 @@ export class IndexActionsContextMenu extends Component { defaultMessage: 'Show index stats', }), onClick: () => { - history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Stats)); + history.push( + getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Stats) + ); }, }); } diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js index 7a15abef3a16f..93db1f9c02e9b 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js @@ -206,6 +206,10 @@ export class IndexTable extends Component { if (error) { this.setState({ filterError: error }); } else { + const { pathname, search } = this.props.location; + const params = qs.parse(search); + params.filter = query.text; + this.props.history.push(pathname + '?' + qs.stringify(params)); this.props.filterChanged(query); this.setState({ filterError: null }); } @@ -282,7 +286,8 @@ export class IndexTable extends Component { } buildRowCell(fieldName, value, index, appServices) { - const { filterChanged, history } = this.props; + const { filterChanged, history, filter } = this.props; + const { includeHiddenIndices } = this.readURLParams(); if (fieldName === 'health') { return ; @@ -291,7 +296,11 @@ export class IndexTable extends Component { history.push(getIndexDetailsLink(value))} + onClick={() => + history.push( + getIndexDetailsLink(value, { filter: filter.text, includeHiddenIndices }) + ) + } > {value} @@ -565,6 +574,10 @@ export class IndexTable extends Component { { this.setState({ selectedIndicesMap: {} }); }} diff --git a/x-pack/plugins/index_management/public/application/services/routing.ts b/x-pack/plugins/index_management/public/application/services/routing.ts index 02e1410e9551c..777d1e423e7d5 100644 --- a/x-pack/plugins/index_management/public/application/services/routing.ts +++ b/x-pack/plugins/index_management/public/application/services/routing.ts @@ -35,27 +35,39 @@ export const getTemplateCloneLink = (name: string, isLegacy?: boolean) => { }; export const getIndexListUri = (filter?: string, includeHiddenIndices?: boolean) => { + let url = `/${Section.Indices}`; const hiddenIndicesParam = typeof includeHiddenIndices !== 'undefined' ? includeHiddenIndices : false; - if (filter) { + if (hiddenIndicesParam) { + url = `${url}?includeHiddenIndices=${hiddenIndicesParam}`; + } + if (filter && filter !== 'undefined') { // React router tries to decode url params but it can't because the browser partially // decodes them. So we have to encode both the URL and the filter to get it all to // work correctly for filters with URL unsafe characters in them. - return encodeURI( - `/indices?includeHiddenIndices=${hiddenIndicesParam}&filter=${encodeURIComponent(filter)}` - ); + url = `${url}${hiddenIndicesParam ? '&' : '?'}filter=${encodeURIComponent(filter)}`; } - // If no filter, URI is already safe so no need to encode. - return '/indices'; + return url; }; export const getDataStreamDetailsLink = (name: string) => { return encodeURI(`/data_streams/${encodeURIComponent(name)}`); }; -export const getIndexDetailsLink = (indexName: string, tab?: IndexDetailsTabId) => { +export const getIndexDetailsLink = ( + indexName: string, + indicesListParams: { filter: string; includeHiddenIndices: boolean }, + tab?: IndexDetailsTabId +) => { let link = `/${Section.Indices}/index_details?indexName=${encodeURIComponent(indexName)}`; + const { filter, includeHiddenIndices } = indicesListParams; + if (filter) { + link = `${link}&filter=${filter}`; + } + if (includeHiddenIndices) { + link = `${link}&includeHiddenIndices=${includeHiddenIndices}`; + } if (tab) { link = `${link}&tab=${tab}`; } From c776c339ee37a02b2bcd9a4a0183c4f53d3e622a Mon Sep 17 00:00:00 2001 From: Yulia Cech Date: Tue, 9 Jan 2024 15:34:21 +0100 Subject: [PATCH 2/6] [Index Management] Add tests --- .../index_details_page.test.tsx | 30 ++++++++++-- .../details_page_overview/aliases_details.tsx | 1 + .../application/services/routing.test.ts | 48 +++++++++++++++++++ .../public/application/services/routing.ts | 2 +- 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 x-pack/plugins/index_management/public/application/services/routing.test.ts diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx index 76a9d9389112e..9988e5addda90 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx @@ -650,11 +650,31 @@ describe('', () => { }); }); - it('navigates back to indices', async () => { - jest.spyOn(testBed.routerMock.history, 'push'); - await testBed.actions.clickBackToIndicesButton(); - expect(testBed.routerMock.history.push).toHaveBeenCalledTimes(1); - expect(testBed.routerMock.history.push).toHaveBeenCalledWith('/indices'); + describe('navigates back to the indices list', () => { + it('without indices list params', async () => { + jest.spyOn(testBed.routerMock.history, 'push'); + await testBed.actions.clickBackToIndicesButton(); + expect(testBed.routerMock.history.push).toHaveBeenCalledTimes(1); + expect(testBed.routerMock.history.push).toHaveBeenCalledWith('/indices'); + }); + it('with indices list params', async () => { + const filter = 'isFollower:true'; + await act(async () => { + testBed = await setup({ + httpSetup, + initialEntry: `/indices/index_details?indexName=${testIndexName}&filter=${encodeURIComponent( + filter + )}&includeHiddenIndices=true`, + }); + }); + testBed.component.update(); + jest.spyOn(testBed.routerMock.history, 'push'); + await testBed.actions.clickBackToIndicesButton(); + expect(testBed.routerMock.history.push).toHaveBeenCalledTimes(1); + expect(testBed.routerMock.history.push).toHaveBeenCalledWith( + `/indices?includeHiddenIndices=true&filter=${encodeURIComponent(filter)}` + ); + }); }); it('renders a link to discover', () => { diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/aliases_details.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/aliases_details.tsx index 8ea5a1fa491ce..934c7c31cdbfa 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/aliases_details.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/aliases_details.tsx @@ -37,6 +37,7 @@ export const AliasesDetails: FunctionComponent<{ aliases: Index['aliases'] }> = } const aliasesBadges = aliases.slice(0, MAX_VISIBLE_ALIASES).map((alias) => ( { + describe('index details link', () => { + it('adds the index name to the url', () => { + const indexName = 'testIndex'; + const url = getIndexDetailsLink(indexName, { filter: '', includeHiddenIndices: false }); + expect(url).toContain(`indexName=${indexName}`); + }); + + it('adds the indices table parameters to the url', () => { + const filter = 'isFollower:true'; + const url = getIndexDetailsLink('testIndex', { filter, includeHiddenIndices: true }); + expect(url).toContain(`filter=${encodeURIComponent(filter)}`); + expect(url).toContain('includeHiddenIndices=true'); + }); + + it('adds an optional index details tab to the url', () => { + const tab = 'dynamic-tab'; + const url = getIndexDetailsLink( + 'testIndex', + { filter: '', includeHiddenIndices: false }, + tab + ); + expect(url).toContain(`tab=${tab}`); + }); + }); + + describe('indices list link', () => { + it('adds filter to the url', () => { + const filter = 'isFollower:true'; + const url = getIndexListUri(filter); + expect(url).toContain(`?filter=${encodeURIComponent(filter)}`); + }); + + it('adds includeHiddenIndices param to the url', () => { + const url = getIndexListUri('', true); + expect(url).toContain(`?includeHiddenIndices=true`); + }); + }); +}); diff --git a/x-pack/plugins/index_management/public/application/services/routing.ts b/x-pack/plugins/index_management/public/application/services/routing.ts index 777d1e423e7d5..6b4e0d71f14c0 100644 --- a/x-pack/plugins/index_management/public/application/services/routing.ts +++ b/x-pack/plugins/index_management/public/application/services/routing.ts @@ -63,7 +63,7 @@ export const getIndexDetailsLink = ( let link = `/${Section.Indices}/index_details?indexName=${encodeURIComponent(indexName)}`; const { filter, includeHiddenIndices } = indicesListParams; if (filter) { - link = `${link}&filter=${filter}`; + link = `${link}&filter=${encodeURIComponent(filter)}`; } if (includeHiddenIndices) { link = `${link}&includeHiddenIndices=${includeHiddenIndices}`; From a58505f6e6f25df1978f9401272ab80282a3f065 Mon Sep 17 00:00:00 2001 From: Yulia Cech Date: Wed, 10 Jan 2024 20:52:40 +0100 Subject: [PATCH 3/6] [Index Management] Refactor the hidden indices toggle and add pagination to the url params --- .../helpers/test_subjects.ts | 2 +- .../client_integration/home/home.helpers.ts | 2 +- .../home/indices_tab.helpers.ts | 4 +- .../index_details_page.test.tsx | 2 +- .../__jest__/components/index_table.test.js | 2 +- .../details_page/details_page_content.tsx | 21 ++-- .../index_actions_context_menu.js | 10 +- .../index_list/index_table/index_table.js | 110 ++++++++++-------- .../application/services/routing.test.ts | 13 +-- .../public/application/services/routing.ts | 10 +- .../application/store/reducers/table_state.js | 1 + .../application/store/selectors/index.d.ts | 2 +- .../application/store/selectors/index.js | 27 ++--- .../store/selectors/indices_filter.test.ts | 21 ++-- .../public/services/extensions_service.ts | 21 +++- .../page_objects/index_management_page.ts | 2 +- 16 files changed, 126 insertions(+), 124 deletions(-) diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts index 52ac8313ef4d0..e26aeae5f1aa3 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/test_subjects.ts @@ -30,7 +30,7 @@ export type TestSubjects = | 'indexContextMenu' | 'indexManagementHeaderContent' | 'indexTable' - | 'indexTableIncludeHiddenIndicesToggle' + | 'checkboxToggles-includeHiddenIndices' | 'indexTableIndexNameLink' | 'indicesList' | 'indicesTab' diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts index 25b1f985d441b..0f1de202f6643 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/home.helpers.ts @@ -44,7 +44,7 @@ export const setup = async (httpSetup: HttpSetup): Promise => { }; const toggleHiddenIndices = async function () { - find('indexTableIncludeHiddenIndicesToggle').simulate('click'); + find('checkboxToggles-includeHiddenIndices').simulate('click'); }; return { diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts index 91a74ff0f558b..0368c06fd3d73 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/indices_tab.helpers.ts @@ -74,7 +74,7 @@ export const setup = async ( const clickIncludeHiddenIndicesToggle = () => { const { find } = testBed; - find('indexTableIncludeHiddenIndicesToggle').simulate('click'); + find('checkboxToggles-includeHiddenIndices').simulate('click'); }; const clickManageContextMenuButton = async () => { @@ -88,7 +88,7 @@ export const setup = async ( const getIncludeHiddenIndicesToggleStatus = () => { const { find } = testBed; - const props = find('indexTableIncludeHiddenIndicesToggle').props(); + const props = find('checkboxToggles-includeHiddenIndices').props(); return Boolean(props['aria-checked']); }; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx index 9988e5addda90..a509870ce6520 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx @@ -672,7 +672,7 @@ describe('', () => { await testBed.actions.clickBackToIndicesButton(); expect(testBed.routerMock.history.push).toHaveBeenCalledTimes(1); expect(testBed.routerMock.history.push).toHaveBeenCalledWith( - `/indices?includeHiddenIndices=true&filter=${encodeURIComponent(filter)}` + `/indices?filter=${encodeURIComponent(filter)}&includeHiddenIndices=true` ); }); }); 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 a3e0dd01f250f..af3333d3201ef 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 @@ -277,7 +277,7 @@ describe('index table', () => { snapshot(indicesInTable); // Enable "Show hidden indices" - const switchControl = findTestSubject(rendered, 'indexTableIncludeHiddenIndicesToggle'); + const switchControl = findTestSubject(rendered, 'checkboxToggles-includeHiddenIndices'); switchControl.simulate('click'); // We do expect now the `.admin1` and `.admin3` indices to be in the list diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx index 7c03dcb0bc186..bbb7c72072755 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx @@ -25,8 +25,9 @@ import { IndexDetailsSection, IndexDetailsTab, IndexDetailsTabId, + Section, } from '../../../../../../common/constants'; -import { getIndexDetailsLink, getIndexListUri } from '../../../../services/routing'; +import { getIndexDetailsLink } from '../../../../services/routing'; import { useAppContext } from '../../../../app_context'; import { DiscoverLink } from '../../../../lib/discover_link'; import { ManageIndexButton } from './manage_index_button'; @@ -110,22 +111,20 @@ export const DetailsPageContent: FunctionComponent = ({ return sortedTabs; }, [enableIndexStats, extensionsService.indexDetailsTabs, index]); - const { filter: filterParam, includeHiddenIndices: includeHiddenParam } = qs.parse(search); - const filter = String(filterParam); - const includeHiddenIndices = Boolean(includeHiddenParam); - const onSectionChange = useCallback( (newSection: IndexDetailsTabId) => { - return history.push( - getIndexDetailsLink(index.name, { filter, includeHiddenIndices }, newSection) - ); + return history.push(getIndexDetailsLink(index.name, search, newSection)); }, - [history, index.name, filter, includeHiddenIndices] + [history, index.name, search] ); const navigateToAllIndices = useCallback(() => { - history.push(getIndexListUri(filter, includeHiddenIndices)); - }, [history, filter, includeHiddenIndices]); + const indicesListParams = qs.parse(search); + delete indicesListParams.indexName; + delete indicesListParams.tab; + const paramsString = qs.stringify(indicesListParams); + history.push(`/${Section.Indices}${paramsString ? '?' : ''}${paramsString}`); + }, [history, search]); const headerTabs = useMemo(() => { return tabs.map((tabConfig) => ({ diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js index b96adabc2b05e..2acce7f28b06f 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_actions_context_menu/index_actions_context_menu.js @@ -68,7 +68,7 @@ export class IndexActionsContextMenu extends Component { indices, reloadIndices, unfreezeIndices, - indicesListParams, + indicesListURLParams, } = this.props; const allOpen = every(indexNames, (indexName) => { return indexStatusByName[indexName] === INDEX_OPEN; @@ -84,7 +84,7 @@ export class IndexActionsContextMenu extends Component { }), onClick: () => { history.push( - getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Overview) + getIndexDetailsLink(indexNames[0], indicesListURLParams, IndexDetailsSection.Overview) ); }, }); @@ -95,7 +95,7 @@ export class IndexActionsContextMenu extends Component { }), onClick: () => { history.push( - getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Settings) + getIndexDetailsLink(indexNames[0], indicesListURLParams, IndexDetailsSection.Settings) ); }, }); @@ -106,7 +106,7 @@ export class IndexActionsContextMenu extends Component { }), onClick: () => { history.push( - getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Mappings) + getIndexDetailsLink(indexNames[0], indicesListURLParams, IndexDetailsSection.Mappings) ); }, }); @@ -118,7 +118,7 @@ export class IndexActionsContextMenu extends Component { }), onClick: () => { history.push( - getIndexDetailsLink(indexNames[0], indicesListParams, IndexDetailsSection.Stats) + getIndexDetailsLink(indexNames[0], indicesListURLParams, IndexDetailsSection.Stats) ); }, }); diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js index 93db1f9c02e9b..5e884a41018e3 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js @@ -50,6 +50,8 @@ import { NoMatch, DataHealth } from '../../../../components'; import { IndexActionsContextMenu } from '../index_actions_context_menu'; import { CreateIndexButton } from '../create_index/create_index_button'; +const PAGE_SIZE_OPTIONS = [10, 50, 100]; + const getHeaders = ({ showIndexStats }) => { const headers = {}; @@ -127,18 +129,30 @@ export class IndexTable extends Component { ), REFRESH_RATE_INDEX_LIST ); - const { location, filterChanged } = this.props; - const { filter } = qs.parse((location && location.search) || ''); + const { filterChanged, pageSizeChanged, pageChanged, toggleNameToVisibleMap, toggleChanged } = + this.props; + const { filter, pageSize, pageIndex, ...rest } = this.readURLParams(); if (filter) { - const decodedFilter = attemptToURIDecode(filter); - try { - const filter = EuiSearchBar.Query.parse(decodedFilter); - filterChanged(filter); + const parsedFilter = EuiSearchBar.Query.parse(filter); + filterChanged(parsedFilter); } catch (e) { this.setState({ filterError: e }); } } + if (pageSize && PAGE_SIZE_OPTIONS.includes(pageSize)) { + pageSizeChanged(pageSize); + } + if (pageIndex && pageIndex > -1) { + pageChanged(pageIndex); + } + const toggleParams = Object.keys(rest); + const toggles = Object.keys(toggleNameToVisibleMap); + for (const toggleParam of toggleParams) { + if (toggles.includes(toggleParam)) { + toggleChanged(toggleParam, rest[toggleParam] === 'true'); + } + } } componentWillUnmount() { @@ -152,21 +166,25 @@ export class IndexTable extends Component { readURLParams() { const { location } = this.props; - const { includeHiddenIndices } = qs.parse((location && location.search) || ''); + const { filter, pageSize, pageIndex, ...rest } = qs.parse((location && location.search) || ''); return { - includeHiddenIndices: includeHiddenIndices === 'true', + filter: filter ? attemptToURIDecode(String(filter)) : undefined, + pageSize: pageSize ? Number(String(pageSize)) : undefined, + pageIndex: pageIndex ? Number(String(pageIndex)) : undefined, + ...rest, }; } - setIncludeHiddenParam(hidden) { - const { pathname, search } = this.props.location; + setURLParam(paramName, value) { + const { location, history } = this.props; + const { pathname, search } = location; const params = qs.parse(search); - if (hidden) { - params.includeHiddenIndices = 'true'; + if (value) { + params[paramName] = value; } else { - delete params.includeHiddenIndices; + delete params[paramName]; } - this.props.history.push(pathname + '?' + qs.stringify(params)); + history.push(pathname + '?' + qs.stringify(params)); } onSort = (column) => { @@ -206,10 +224,7 @@ export class IndexTable extends Component { if (error) { this.setState({ filterError: error }); } else { - const { pathname, search } = this.props.location; - const params = qs.parse(search); - params.filter = query.text; - this.props.history.push(pathname + '?' + qs.stringify(params)); + this.setURLParam('filter', encodeURIComponent(query.text)); this.props.filterChanged(query); this.setState({ filterError: null }); } @@ -286,8 +301,7 @@ export class IndexTable extends Component { } buildRowCell(fieldName, value, index, appServices) { - const { filterChanged, history, filter } = this.props; - const { includeHiddenIndices } = this.readURLParams(); + const { filterChanged, history, location } = this.props; if (fieldName === 'health') { return ; @@ -296,11 +310,7 @@ export class IndexTable extends Component { - history.push( - getIndexDetailsLink(value, { filter: filter.text, includeHiddenIndices }) - ) - } + onClick={() => history.push(getIndexDetailsLink(value, location.search || ''))} > {value} @@ -425,10 +435,16 @@ export class IndexTable extends Component { { + this.setURLParam('pageSize', pageSize); + pageSizeChanged(pageSize); + }} + onChangePage={(pageIndex) => { + this.setURLParam('pageIndex', pageIndex); + pageChanged(pageIndex); + }} /> ); } @@ -445,7 +461,10 @@ export class IndexTable extends Component { id={`checkboxToggles-${name}`} data-test-subj={`checkboxToggles-${name}`} checked={toggleNameToVisibleMap[name]} - onChange={(event) => toggleChanged(name, event.target.checked)} + onChange={(event) => { + this.setURLParam(name, event.target.checked); + toggleChanged(name, event.target.checked); + }} label={label} /> @@ -453,10 +472,17 @@ export class IndexTable extends Component { } render() { - const { filter, indices, loadIndices, indicesLoading, indicesError, allIndices, pager } = - this.props; + const { + filter, + indices, + loadIndices, + indicesLoading, + indicesError, + allIndices, + pager, + location, + } = this.props; - const { includeHiddenIndices } = this.readURLParams(); const hasContent = !indicesLoading && !indicesError; if (!hasContent) { @@ -541,21 +567,6 @@ export class IndexTable extends Component { {extensionsService.toggles.map((toggle) => { return this.renderToggleControl(toggle); })} - - - this.setIncludeHiddenParam(event.target.checked)} - label={ - - } - /> - )} @@ -574,10 +585,7 @@ export class IndexTable extends Component { { this.setState({ selectedIndicesMap: {} }); }} diff --git a/x-pack/plugins/index_management/public/application/services/routing.test.ts b/x-pack/plugins/index_management/public/application/services/routing.test.ts index e6087be02e4c4..24500cb6059bf 100644 --- a/x-pack/plugins/index_management/public/application/services/routing.test.ts +++ b/x-pack/plugins/index_management/public/application/services/routing.test.ts @@ -11,24 +11,19 @@ describe('routing', () => { describe('index details link', () => { it('adds the index name to the url', () => { const indexName = 'testIndex'; - const url = getIndexDetailsLink(indexName, { filter: '', includeHiddenIndices: false }); + const url = getIndexDetailsLink(indexName, ''); expect(url).toContain(`indexName=${indexName}`); }); it('adds the indices table parameters to the url', () => { const filter = 'isFollower:true'; - const url = getIndexDetailsLink('testIndex', { filter, includeHiddenIndices: true }); - expect(url).toContain(`filter=${encodeURIComponent(filter)}`); - expect(url).toContain('includeHiddenIndices=true'); + const url = getIndexDetailsLink('testIndex', `?filter=${encodeURIComponent(filter)}`); + expect(url).toContain(`&filter=${encodeURIComponent(filter)}`); }); it('adds an optional index details tab to the url', () => { const tab = 'dynamic-tab'; - const url = getIndexDetailsLink( - 'testIndex', - { filter: '', includeHiddenIndices: false }, - tab - ); + const url = getIndexDetailsLink('testIndex', '', tab); expect(url).toContain(`tab=${tab}`); }); }); diff --git a/x-pack/plugins/index_management/public/application/services/routing.ts b/x-pack/plugins/index_management/public/application/services/routing.ts index 6b4e0d71f14c0..a2d4a03013556 100644 --- a/x-pack/plugins/index_management/public/application/services/routing.ts +++ b/x-pack/plugins/index_management/public/application/services/routing.ts @@ -57,16 +57,12 @@ export const getDataStreamDetailsLink = (name: string) => { export const getIndexDetailsLink = ( indexName: string, - indicesListParams: { filter: string; includeHiddenIndices: boolean }, + indicesListURLParams: string, tab?: IndexDetailsTabId ) => { let link = `/${Section.Indices}/index_details?indexName=${encodeURIComponent(indexName)}`; - const { filter, includeHiddenIndices } = indicesListParams; - if (filter) { - link = `${link}&filter=${encodeURIComponent(filter)}`; - } - if (includeHiddenIndices) { - link = `${link}&includeHiddenIndices=${includeHiddenIndices}`; + if (indicesListURLParams) { + link = `${link}&${indicesListURLParams.replace('?', '')}`; } if (tab) { link = `${link}&tab=${tab}`; diff --git a/x-pack/plugins/index_management/public/application/store/reducers/table_state.js b/x-pack/plugins/index_management/public/application/store/reducers/table_state.js index c07ed875ee6e7..e5a5627300fbf 100644 --- a/x-pack/plugins/index_management/public/application/store/reducers/table_state.js +++ b/x-pack/plugins/index_management/public/application/store/reducers/table_state.js @@ -20,6 +20,7 @@ export const defaultTableState = { currentPage: 0, sortField: 'index.name', isSortAscending: true, + toggleNameToVisibleMap: {}, }; export const tableState = handleActions( diff --git a/x-pack/plugins/index_management/public/application/store/selectors/index.d.ts b/x-pack/plugins/index_management/public/application/store/selectors/index.d.ts index 65d72ef26cfda..e33fff1864a64 100644 --- a/x-pack/plugins/index_management/public/application/store/selectors/index.d.ts +++ b/x-pack/plugins/index_management/public/application/store/selectors/index.d.ts @@ -9,4 +9,4 @@ import { ExtensionsService } from '../../../services'; export declare function setExtensionsService(extensionsService: ExtensionsService): any; -export const getFilteredIndices: (state: any, props: any) => any; +export const getFilteredIndices: (state: any) => any; diff --git a/x-pack/plugins/index_management/public/application/store/selectors/index.js b/x-pack/plugins/index_management/public/application/store/selectors/index.js index 57ba47205e012..6ed09d8234fa4 100644 --- a/x-pack/plugins/index_management/public/application/store/selectors/index.js +++ b/x-pack/plugins/index_management/public/application/store/selectors/index.js @@ -8,9 +8,7 @@ import { Pager, EuiSearchBar } from '@elastic/eui'; import { createSelector } from 'reselect'; -import * as qs from 'query-string'; import { indexStatusLabels } from '../../lib/index_status_labels'; -import { isHiddenIndex } from '../../lib/indices'; import { sortTable } from '../../services'; import { extensionsService } from './extension_service'; @@ -50,16 +48,15 @@ const filterByToggles = (indices, toggleNameToVisibleMap) => { if (!toggleNames.length) { return indices; } - // An index is visible if ANY applicable toggle is visible. return indices.filter((index) => { - return toggleNames.some((toggleName) => { - if (!togglesByName[toggleName].matchIndex(index)) { - return true; + return toggleNames.every((toggleName) => { + // if an index matches a toggle, it's only shown if the toggle is set to "enabled" + // for example, a hidden index is only shown when the "include hidden" toggle is "enabled" + if (togglesByName[toggleName].matchIndex(index)) { + return toggleNameToVisibleMap[toggleName] === true; } - - const isVisible = toggleNameToVisibleMap[toggleName] === true; - - return isVisible; + // otherwise the index is shown by default + return true; }); }); }; @@ -68,17 +65,11 @@ export const getFilteredIndices = createSelector( getIndices, getAllIds, getTableState, - getTableLocationProp, - (indices, allIds, tableState, tableLocation) => { + (indices, allIds, tableState) => { let indexArray = allIds.map((indexName) => indices[indexName]); indexArray = filterByToggles(indexArray, tableState.toggleNameToVisibleMap); - const { includeHiddenIndices: includeHiddenParam } = qs.parse(tableLocation.search); - const includeHidden = includeHiddenParam === 'true'; - const filteredIndices = includeHidden - ? indexArray - : indexArray.filter((index) => !isHiddenIndex(index)); const filter = tableState.filter || EuiSearchBar.Query.MATCH_ALL; - return EuiSearchBar.Query.execute(filter, filteredIndices, { + return EuiSearchBar.Query.execute(filter, indexArray, { defaultFields: defaultFilterFields, }); } diff --git a/x-pack/plugins/index_management/public/application/store/selectors/indices_filter.test.ts b/x-pack/plugins/index_management/public/application/store/selectors/indices_filter.test.ts index bdb531e41abb2..adb078674755d 100644 --- a/x-pack/plugins/index_management/public/application/store/selectors/indices_filter.test.ts +++ b/x-pack/plugins/index_management/public/application/store/selectors/indices_filter.test.ts @@ -4,17 +4,13 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import SemVer from 'semver/classes/semver'; -import { MAJOR_VERSION } from '../../../../common'; import { ExtensionsService } from '../../../services'; import { getFilteredIndices } from '.'; // @ts-ignore import { defaultTableState } from '../reducers/table_state'; import { setExtensionsService } from './extension_service'; -const kibanaVersion = new SemVer(MAJOR_VERSION); - describe('getFilteredIndices selector', () => { let extensionService: ExtensionsService; beforeAll(() => { @@ -37,19 +33,20 @@ describe('getFilteredIndices selector', () => { }; it('filters out hidden indices', () => { - let expected = [{ name: 'index2', hidden: false }, { name: 'index3' }, { name: '.index4' }]; - - if (kibanaVersion.major < 8) { - // In 7.x index name starting with a dot are considered hidden indices - expected = [{ name: 'index2', hidden: false }, { name: 'index3' }]; - } + const expected = [{ name: 'index2', hidden: false }, { name: 'index3' }, { name: '.index4' }]; - expect(getFilteredIndices(state, { location: { search: '' } })).toEqual(expected); + expect(getFilteredIndices(state)).toEqual(expected); }); it('includes hidden indices', () => { expect( - getFilteredIndices(state, { location: { search: '?includeHiddenIndices=true' } }) + getFilteredIndices({ + ...state, + tableState: { + ...defaultTableState, + toggleNameToVisibleMap: { includeHiddenIndices: true }, + }, + }) ).toEqual([ { name: 'index1', hidden: true }, { name: 'index2', hidden: false }, diff --git a/x-pack/plugins/index_management/public/services/extensions_service.ts b/x-pack/plugins/index_management/public/services/extensions_service.ts index 1eb68e9a0b746..e78b355a56d15 100644 --- a/x-pack/plugins/index_management/public/services/extensions_service.ts +++ b/x-pack/plugins/index_management/public/services/extensions_service.ts @@ -19,6 +19,11 @@ export interface IndexContent { }) => ReturnType; } +export interface IndexToggle { + matchIndex: (index: Index) => boolean; + label: string; + name: string; +} export interface IndexBadge { matchIndex: (index: Index) => boolean; label: string; @@ -37,7 +42,7 @@ export interface ExtensionsSetup { // adds a badge to the index name addBadge(badge: IndexBadge): void; // adds a toggle to the indices list - addToggle(toggle: any): void; + addToggle(toggle: IndexToggle): void; // adds a tab to the index details page addIndexDetailsTab(tab: IndexDetailsTab): void; // sets content to render instead of the code block on the overview tab of the index page @@ -52,7 +57,7 @@ export class ExtensionsService { private _filters: any[] = []; private _badges: IndexBadge[] = [ { - matchIndex: (index: { isFrozen: boolean }) => { + matchIndex: (index) => { return index.isFrozen; }, label: i18n.translate('xpack.idxMgmt.frozenBadgeLabel', { @@ -62,7 +67,17 @@ export class ExtensionsService { color: 'primary', }, ]; - private _toggles: any[] = []; + private _toggles: IndexToggle[] = [ + { + matchIndex: (index) => { + return index.hidden; + }, + label: i18n.translate('xpack.idxMgmt.indexTable.hiddenIndicesSwitchLabel', { + defaultMessage: 'Include hidden indices', + }), + name: 'includeHiddenIndices', + }, + ]; private _indexDetailsTabs: IndexDetailsTab[] = []; private _indexOverviewContent: IndexContent | null = null; private _indexMappingsContent: IndexContent | null = null; 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 19eb3f2824f3a..718dac14221ac 100644 --- a/x-pack/test/functional/page_objects/index_management_page.ts +++ b/x-pack/test/functional/page_objects/index_management_page.ts @@ -23,7 +23,7 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext) return await testSubjects.find('reloadIndicesButton'); }, async toggleHiddenIndices() { - await testSubjects.click('indexTableIncludeHiddenIndicesToggle'); + await testSubjects.click('checkboxToggles-includeHiddenIndices'); }, async clickEnrichPolicyAt(indexOfRow: number): Promise { From 2ba2be4da06f31a7e4868a10e3b0a10184405662 Mon Sep 17 00:00:00 2001 From: Yulia Cech Date: Thu, 11 Jan 2024 10:53:06 +0100 Subject: [PATCH 4/6] [Index Management] Fix types --- .../rollup/public/extend_index_management/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/rollup/public/extend_index_management/index.ts b/x-pack/plugins/rollup/public/extend_index_management/index.ts index b285db2b9ca76..116d7b38996f8 100644 --- a/x-pack/plugins/rollup/public/extend_index_management/index.ts +++ b/x-pack/plugins/rollup/public/extend_index_management/index.ts @@ -7,12 +7,10 @@ import { i18n } from '@kbn/i18n'; import { Index } from '@kbn/index-management-plugin/common'; -import { get } from 'lodash'; -const propertyPath = 'isRollupIndex'; export const rollupToggleExtension = { - matchIndex: (index: { isRollupIndex: boolean }) => { - return get(index, propertyPath); + matchIndex: (index: Index) => { + return Boolean(index.isRollupIndex); }, label: i18n.translate('xpack.rollupJobs.indexMgmtToggle.toggleLabel', { defaultMessage: 'Include rollup indices', @@ -22,7 +20,7 @@ export const rollupToggleExtension = { export const rollupBadgeExtension = { matchIndex: (index: Index) => { - return !!get(index, propertyPath); + return Boolean(index.isRollupIndex); }, label: i18n.translate('xpack.rollupJobs.indexMgmtBadge.rollupLabel', { defaultMessage: 'Rollup', From 25ec028552808878f22e914cc9950aeed0022943 Mon Sep 17 00:00:00 2001 From: Yulia Cech Date: Wed, 17 Jan 2024 11:01:27 +0100 Subject: [PATCH 5/6] [Index Management] Fix merge conflicts --- .../home/index_list/details_page/details_page.tsx | 10 ++++++++-- .../index_list/details_page/details_page_content.tsx | 1 - 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx index 7872f2eacda78..52572faea21ad 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx @@ -6,6 +6,7 @@ */ import React, { useCallback, useEffect, useMemo, useState, FunctionComponent } from 'react'; +import qs from 'query-string'; import { RouteComponentProps } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiPageTemplate, EuiText, EuiCode } from '@elastic/eui'; @@ -34,8 +35,12 @@ export const DetailsPage: FunctionComponent< const [index, setIndex] = useState(); const navigateToIndicesList = useCallback(() => { - history.push(`/${Section.Indices}`); - }, [history]); + const indicesListParams = qs.parse(search); + delete indicesListParams.indexName; + delete indicesListParams.tab; + const paramsString = qs.stringify(indicesListParams); + history.push(`/${Section.Indices}${paramsString ? '?' : ''}${paramsString}`); + }, [history, search]); const fetchIndexDetails = useCallback(async () => { if (indexName) { @@ -109,6 +114,7 @@ export const DetailsPage: FunctionComponent< tab={tab} fetchIndexDetails={fetchIndexDetails} history={history} + search={search} navigateToIndicesList={navigateToIndicesList} /> ); diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx index 62f96007e271e..447c3ff330bac 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx @@ -17,7 +17,6 @@ import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import { RouteComponentProps } from 'react-router-dom'; -import qs from 'query-string'; import { renderBadges } from '../../../../lib/render_badges'; import { Index } from '../../../../../../common'; import { From 59c0a35ffccf6878eb08f0a2d4ae6205329b4c12 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:29:47 +0000 Subject: [PATCH 6/6] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../sections/home/index_list/index_table/index_table.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js index eb0315225d1db..137c4b8ca67e0 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js @@ -120,11 +120,11 @@ export class IndexTable extends Component { componentDidMount() { this.props.loadIndices(); - + const { filterChanged, pageSizeChanged, pageChanged, toggleNameToVisibleMap, toggleChanged } = this.props; const { filter, pageSize, pageIndex, ...rest } = this.readURLParams(); - + if (filter) { try { const parsedFilter = EuiSearchBar.Query.parse(filter);