Fix bug in Index Management ILM details (#213101)

## Summary
We had a bug in Index Management. When the user clicks Index Management
> Index details > Index lifecycle, the page was unable to load. After
refreshing, the info was displayed correctly.

![image](https://github.com/user-attachments/assets/924e59cc-2912-4e3c-aaf3-8e2cc3adfe33)
 
This error was caused because the hook invariant violation rule was not
being fulfilled: https://react.dev/errors/310?invariant=310.

The lifecycle tab is rendered through the extension service that comes
from the ILM plugin. In [this
PR](https://github.com/elastic/kibana/pull/204449/files#diff-021836407481af0b98d7d91abab452bed569e3197072713bdf57a065f43ef734R43)
we modified the ILM component introducing the `euiTheme` hook, which was
causing the the hook invariant violation error.

With this PR the hook is now rendered in the Index Management plugin and
passed to ILM to avoid the error.

### Demo
<details>
<summary>Video</summary>



https://github.com/user-attachments/assets/2c212d30-b7a9-42de-9869-cc10093f0f33


</details>

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Sonia Sanz Vivas 2025-03-07 13:43:09 +01:00 committed by GitHub
parent 5d565abd02
commit 521f34511e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 47 additions and 26 deletions

View file

@ -7,7 +7,7 @@
import { FunctionComponent, ReactNode } from 'react';
import type { ApplicationStart } from '@kbn/core-application-browser';
import { EuiBreadcrumb } from '@elastic/eui';
import { EuiBreadcrumb, EuiThemeComputed } from '@elastic/eui';
import { Index } from './types';
export enum Section {
@ -36,6 +36,7 @@ export interface IndexDetailsTab {
renderTabContent: (args: {
index: Index;
getUrlForApp: ApplicationStart['getUrlForApp'];
euiTheme: EuiThemeComputed;
}) => ReturnType<FunctionComponent>;
// a number to specify the order of the tabs
order: number;

View file

@ -179,7 +179,7 @@ exports[`extend index management ilm summary extension should render a phase def
>
<span
class="euiBadge emotion-euiBadge"
style="--euiBadgeBackgroundColor: #F6726A; --euiBadgeTextColor: #07101F;"
style="--euiBadgeBackgroundColor: #B9A888; --euiBadgeTextColor: #07101F;"
title="Hot"
>
<span
@ -349,7 +349,7 @@ exports[`extend index management ilm summary extension should render a step info
>
<span
class="euiBadge emotion-euiBadge"
style="--euiBadgeBackgroundColor: #F6726A; --euiBadgeTextColor: #07101F;"
style="--euiBadgeBackgroundColor: #B9A888; --euiBadgeTextColor: #07101F;"
title="Hot"
>
<span
@ -515,7 +515,7 @@ exports[`extend index management ilm summary extension should render an error pa
>
<span
class="euiBadge emotion-euiBadge"
style="--euiBadgeBackgroundColor: #F6726A; --euiBadgeTextColor: #07101F;"
style="--euiBadgeBackgroundColor: #B9A888; --euiBadgeTextColor: #07101F;"
title="Hot"
>
<span

View file

@ -23,6 +23,7 @@ import { init as initUiMetric } from '../public/application/services/ui_metric';
import { indexLifecycleTab } from '../public/extend_index_management/components/index_lifecycle_summary';
import { Index } from '@kbn/index-management-plugin/common';
import { findTestSubject } from '@elastic/eui/lib/test';
import { useEuiTheme } from '@elastic/eui';
const { httpSetup } = init();
@ -34,6 +35,26 @@ jest.mock('@kbn/index-management-plugin/public', async () => {
return indexManagementMock.createSetup();
});
// Mock useEuiTheme to return the desired theme
jest.mock('@elastic/eui', () => ({
...jest.requireActual('@elastic/eui'),
useEuiTheme: () => ({
euiTheme: {
themeName: 'EUI_THEME_BOREALIS',
colors: {
vis: {
euiColorVis1: '#6092C0',
euiColorVis2: '#D36086',
euiColorVis4: '#CA8EAE',
euiColorVis5: '#D6BF57',
euiColorVis6: '#B9A888',
euiColorVis9: '#E7664C',
},
},
},
}),
}));
const indexWithoutLifecyclePolicy: Index = {
health: 'yellow',
status: 'open',
@ -329,6 +350,11 @@ describe('extend index management', () => {
const policyErrorPanel = 'policyErrorPanel';
const phaseDefinitionPanel = 'phaseDefinitionPanel';
const IlmContentComponent = ({ index }: { index: Index }) => {
const { euiTheme } = useEuiTheme();
return <IlmComponent index={index} getUrlForApp={getUrlForApp} euiTheme={euiTheme} />;
};
test('should not render the tab when index has no index lifecycle policy', () => {
const shouldRenderTab =
indexLifecycleTab.shouldRenderTab &&
@ -345,10 +371,7 @@ describe('extend index management', () => {
index: indexWithLifecyclePolicy,
});
expect(shouldRenderTab).toBeTruthy();
const ilmContent = (
<IlmComponent index={indexWithLifecyclePolicy} getUrlForApp={getUrlForApp} />
);
const rendered = mountWithIntl(ilmContent);
const rendered = mountWithIntl(<IlmContentComponent index={indexWithLifecyclePolicy} />);
expect(rendered.render()).toMatchSnapshot();
expect(findTestSubject(rendered, policyPropertiesPanel).exists()).toBeTruthy();
expect(findTestSubject(rendered, phaseDefinitionPanel).exists()).toBeFalsy();
@ -357,10 +380,7 @@ describe('extend index management', () => {
});
test('should render an error panel when index has lifecycle error', () => {
const ilmContent = (
<IlmComponent index={indexWithLifecycleError} getUrlForApp={getUrlForApp} />
);
const rendered = mountWithIntl(ilmContent);
const rendered = mountWithIntl(<IlmContentComponent index={indexWithLifecycleError} />);
expect(rendered.render()).toMatchSnapshot();
expect(findTestSubject(rendered, policyPropertiesPanel).exists()).toBeTruthy();
expect(findTestSubject(rendered, phaseDefinitionPanel).exists()).toBeFalsy();
@ -369,10 +389,9 @@ describe('extend index management', () => {
});
test('should render a phase definition panel when lifecycle has phase definition', () => {
const ilmContent = (
<IlmComponent index={indexWithLifecyclePhaseDefinition} getUrlForApp={getUrlForApp} />
const rendered = mountWithIntl(
<IlmContentComponent index={indexWithLifecyclePhaseDefinition} />
);
const rendered = mountWithIntl(ilmContent);
expect(rendered.render()).toMatchSnapshot();
expect(findTestSubject(rendered, policyPropertiesPanel).exists()).toBeTruthy();
expect(findTestSubject(rendered, phaseDefinitionPanel).exists()).toBeTruthy();
@ -381,10 +400,7 @@ describe('extend index management', () => {
});
test('should render a step info panel when lifecycle is waiting for a step completion', () => {
const ilmContent = (
<IlmComponent index={indexWithLifecycleWaitingStep} getUrlForApp={getUrlForApp} />
);
const rendered = mountWithIntl(ilmContent);
const rendered = mountWithIntl(<IlmContentComponent index={indexWithLifecycleWaitingStep} />);
expect(rendered.render()).toMatchSnapshot();
expect(findTestSubject(rendered, policyPropertiesPanel).exists()).toBeTruthy();
expect(findTestSubject(rendered, phaseDefinitionPanel).exists()).toBeFalsy();

View file

@ -22,7 +22,7 @@ import {
EuiBadgeProps,
EuiBadge,
EuiCode,
useEuiTheme,
EuiThemeComputed,
} from '@elastic/eui';
import { ApplicationStart } from '@kbn/core/public';
@ -33,15 +33,17 @@ import { getPolicyEditPath } from '../../application/services/navigation';
interface Props {
index: Index;
getUrlForApp: ApplicationStart['getUrlForApp'];
euiTheme: EuiThemeComputed;
}
export const IndexLifecycleSummary: FunctionComponent<Props> = ({ index, getUrlForApp }) => {
export const IndexLifecycleSummary: FunctionComponent<Props> = ({
index,
getUrlForApp,
euiTheme,
}) => {
const { ilm: ilmData } = index;
// only ILM managed indices render the ILM tab
const ilm = ilmData as IlmExplainLifecycleLifecycleExplainManaged;
const { euiTheme } = useEuiTheme();
const isBorealis = euiTheme.themeName === 'EUI_THEME_BOREALIS';
// Changing the mappings for the phases in Borealis as a mid-term solution. See https://github.com/elastic/kibana/issues/203664#issuecomment-2536593361.

View file

@ -6,7 +6,7 @@
*/
import React, { FunctionComponent, useEffect } from 'react';
import { EuiBreadcrumb } from '@elastic/eui';
import { EuiBreadcrumb, useEuiTheme } from '@elastic/eui';
import { breadcrumbService, IndexManagementBreadcrumb } from '../../../../services/breadcrumbs';
import { Index } from '../../../../../../common';
import { IndexDetailsTab, IndexDetailsTabId } from '../../../../../../common/constants';
@ -24,13 +24,15 @@ export const DetailsPageTab: FunctionComponent<Props> = ({ tabs, tab, index }) =
core: { getUrlForApp },
} = useAppContext();
const { euiTheme } = useEuiTheme();
useEffect(() => {
const breadcrumb: EuiBreadcrumb = selectedTab?.breadcrumb ?? { text: selectedTab?.name };
breadcrumbService.setBreadcrumbs(IndexManagementBreadcrumb.indexDetails, breadcrumb);
}, [selectedTab]);
return selectedTab ? (
selectedTab.renderTabContent({ index, getUrlForApp })
selectedTab.renderTabContent({ index, getUrlForApp, euiTheme })
) : (
<DetailsPageOverview indexDetails={index} />
);