mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[SecuritySolution][Navigation] Prevent initial re-render using project nav (#201431)
## Summary Prevents an initial re-render when the `project` navigation style is set (serverless and new solution nav for stateful). This re-render was affecting all the top-level pages in Security Solution. --------- Co-authored-by: Michael Olorunnisola <michael.olorunnisola@elastic.co>
This commit is contained in:
parent
cdeb1e9844
commit
d3ee297d9f
4 changed files with 66 additions and 36 deletions
|
@ -22,32 +22,11 @@ jest.mock('./timeline', () => ({
|
|||
Timeline: () => <div>{'Timeline'}</div>,
|
||||
}));
|
||||
|
||||
jest.mock('../../../common/components/navigation/use_security_solution_navigation', () => {
|
||||
return {
|
||||
useSecuritySolutionNavigation: () => ({
|
||||
icon: 'logoSecurity',
|
||||
items: [
|
||||
{
|
||||
id: 'investigate',
|
||||
name: 'Investigate',
|
||||
items: [
|
||||
{
|
||||
'data-href': 'some-data-href',
|
||||
'data-test-subj': 'navigation-cases',
|
||||
disabled: false,
|
||||
href: 'some-href',
|
||||
id: 'cases',
|
||||
isSelected: true,
|
||||
name: 'Cases',
|
||||
},
|
||||
],
|
||||
tabIndex: undefined,
|
||||
},
|
||||
],
|
||||
name: 'Security',
|
||||
}),
|
||||
};
|
||||
});
|
||||
const navProps = { icon: 'logoSecurity', items: [], name: 'Security' };
|
||||
const mockUseSecuritySolutionNavigation = jest.fn();
|
||||
jest.mock('../../../common/components/navigation/use_security_solution_navigation', () => ({
|
||||
useSecuritySolutionNavigation: () => mockUseSecuritySolutionNavigation(),
|
||||
}));
|
||||
|
||||
const mockUseRouteSpy = jest.fn((): [{ pageName: string }] => [
|
||||
{ pageName: SecurityPageName.alerts },
|
||||
|
@ -69,6 +48,39 @@ const renderComponent = ({
|
|||
describe('SecuritySolutionTemplateWrapper', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockUseSecuritySolutionNavigation.mockReturnValue(navProps);
|
||||
});
|
||||
|
||||
describe('when navigation props are defined (classic nav)', () => {
|
||||
beforeEach(() => {
|
||||
mockUseSecuritySolutionNavigation.mockReturnValue(navProps);
|
||||
});
|
||||
it('should render the children', async () => {
|
||||
const { queryByText } = renderComponent();
|
||||
expect(queryByText('child of wrapper')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when navigation props are null (project nav)', () => {
|
||||
beforeEach(() => {
|
||||
mockUseSecuritySolutionNavigation.mockReturnValue(null);
|
||||
});
|
||||
|
||||
it('should render the children', async () => {
|
||||
const { queryByText } = renderComponent();
|
||||
expect(queryByText('child of wrapper')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when navigation props are undefined (loading)', () => {
|
||||
beforeEach(() => {
|
||||
mockUseSecuritySolutionNavigation.mockReturnValue(undefined);
|
||||
});
|
||||
|
||||
it('should not render the children', async () => {
|
||||
const { queryByText } = renderComponent();
|
||||
expect(queryByText('child of wrapper')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render with bottom bar when user allowed', async () => {
|
||||
|
|
|
@ -69,8 +69,8 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateW
|
|||
const { euiTheme, colorMode: globalColorMode } = useEuiTheme();
|
||||
|
||||
// There is some logic in the StyledKibanaPageTemplate that checks for children presence, and we dont even need to render the children
|
||||
// here if isEmptyState is set
|
||||
const isNotEmpty = !rest.isEmptyState;
|
||||
// solutionNavProps is momentarily initialized to undefined, this check prevents the children from being re-rendered in the initial load
|
||||
const renderChildren = !rest.isEmptyState && solutionNavProps !== undefined;
|
||||
|
||||
/*
|
||||
* StyledKibanaPageTemplate is a styled EuiPageTemplate. Security solution currently passes the header
|
||||
|
@ -83,11 +83,11 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateW
|
|||
theme={euiTheme}
|
||||
$isShowingTimelineOverlay={isShowingTimelineOverlay}
|
||||
paddingSize="none"
|
||||
solutionNav={solutionNavProps}
|
||||
solutionNav={solutionNavProps ?? undefined}
|
||||
restrictWidth={false}
|
||||
{...rest}
|
||||
>
|
||||
{isNotEmpty && (
|
||||
{renderChildren && (
|
||||
<>
|
||||
<GlobalKQLHeader />
|
||||
<KibanaPageTemplate.Section
|
||||
|
|
|
@ -34,6 +34,20 @@ describe('Security Solution Navigation', () => {
|
|||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('while chrome style is undefined', () => {
|
||||
beforeAll(() => {
|
||||
mockGetChromeStyle$.mockReturnValue(of());
|
||||
});
|
||||
|
||||
it('should return proper navigation props', async () => {
|
||||
const { result } = renderHook(useSecuritySolutionNavigation);
|
||||
expect(result.current).toEqual(undefined);
|
||||
|
||||
// check rendering of SecuritySideNav children
|
||||
expect(mockSecuritySideNav).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when classic navigation is enabled', () => {
|
||||
beforeAll(() => {
|
||||
mockGetChromeStyle$.mockReturnValue(of('classic'));
|
||||
|
@ -77,9 +91,9 @@ describe('Security Solution Navigation', () => {
|
|||
mockGetChromeStyle$.mockReturnValue(of('project'));
|
||||
});
|
||||
|
||||
it('should return undefined props when disabled', () => {
|
||||
it('should return null props when disabled', () => {
|
||||
const { result } = renderHook(useSecuritySolutionNavigation);
|
||||
expect(result.current).toEqual(undefined);
|
||||
expect(result.current).toEqual(null);
|
||||
});
|
||||
|
||||
it('should initialize breadcrumbs', () => {
|
||||
|
|
|
@ -23,16 +23,20 @@ const translatedNavTitle = i18n.translate('xpack.securitySolution.navigation.mai
|
|||
defaultMessage: 'Security',
|
||||
});
|
||||
|
||||
export const useSecuritySolutionNavigation = (): KibanaPageTemplateProps['solutionNav'] => {
|
||||
export const useSecuritySolutionNavigation = (): KibanaPageTemplateProps['solutionNav'] | null => {
|
||||
const { chrome } = useKibana().services;
|
||||
const chromeStyle$ = useMemo(() => chrome.getChromeStyle$(), [chrome]);
|
||||
const chromeStyle = useObservable(chromeStyle$, 'classic');
|
||||
const chromeStyle = useObservable(chromeStyle$, undefined);
|
||||
|
||||
useBreadcrumbsNav();
|
||||
|
||||
if (chromeStyle === undefined) {
|
||||
return undefined; // wait for chromeStyle to be initialized
|
||||
}
|
||||
|
||||
if (chromeStyle === 'project') {
|
||||
// new shared-ux 'project' navigation enabled, return undefined to disable the 'classic' navigation
|
||||
return undefined;
|
||||
// new shared-ux 'project' navigation enabled, return null to disable the 'classic' navigation
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue