[Security Solution] Exp flyout expandable widget rendering (#160625)

## Summary

This tiny PR ensures that widget contents are not rendered until
expanded (in the expandable flyout). This will
prevent unnecessary requests being sent when we open the flyout.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Luke 2023-07-05 15:20:55 +02:00 committed by GitHub
parent bc4ffb6634
commit 901b9eb127
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 13 deletions

View file

@ -27,6 +27,12 @@ export interface ExpandableFlyoutProps extends EuiFlyoutProps {
handleOnFlyoutClosed?: () => void;
}
const flyoutStyles = css`
overflow-y: scroll;
`;
const flyoutInnerStyles = { height: '100%' };
/**
* Expandable flyout UI React component.
* Displays 3 sections (right, left, preview) depending on the panels in the context.
@ -65,9 +71,10 @@ export const ExpandableFlyout: React.FC<ExpandableFlyoutProps> = ({
[mostRecentPreview, registeredPanels]
);
// do not add the flyout to the dom if there aren't any panels to display
if (!left && !right && !preview.length) {
return <></>;
const hideFlyout = !left && !right && !preview.length;
if (hideFlyout) {
return null;
}
const flyoutWidth: string = leftSection && rightSection ? 'l' : 's';
@ -77,9 +84,7 @@ export const ExpandableFlyout: React.FC<ExpandableFlyoutProps> = ({
return (
<EuiFlyout
css={css`
overflow-y: scroll;
`}
css={flyoutStyles}
{...flyoutProps}
size={flyoutWidth}
ownFocus={false}
@ -89,7 +94,7 @@ export const ExpandableFlyout: React.FC<ExpandableFlyoutProps> = ({
direction={leftSection ? 'row' : 'column'}
wrap={false}
gutterSize="none"
style={{ height: '100%' }}
style={flyoutInnerStyles}
>
{leftSection && left ? (
<LeftSection

View file

@ -46,6 +46,7 @@ describe(
waitForAlertsToPopulate();
expandFirstAlertExpandableFlyout();
expandDocumentDetailsExpandableFlyoutLeftSection();
createNewCaseFromExpandableFlyout();
openInsightsTab();
openCorrelationsTab();
});
@ -53,8 +54,6 @@ describe(
it('should render correlations details correctly', () => {
cy.log('link the alert to a new case');
createNewCaseFromExpandableFlyout();
cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB).scrollIntoView();
cy.log('should render the Insights header');

View file

@ -6,8 +6,8 @@
*/
import { EuiAccordion, EuiFlexGroup, EuiSpacer, EuiTitle, useGeneratedHtmlId } from '@elastic/eui';
import type { VFC } from 'react';
import React from 'react';
import React, { type VFC } from 'react';
import { useAccordionState } from '../hooks/use_accordion_state';
export const HEADER_TEST_ID = 'Header';
export const CONTENT_TEST_ID = 'Content';
@ -46,6 +46,8 @@ export const ExpandableSection: VFC<DescriptionSectionProps> = ({
}) => {
const accordionId = useGeneratedHtmlId({ prefix: 'accordion' });
const { renderContent, toggle, state } = useAccordionState(expanded);
const headerDataTestSub = dataTestSub + HEADER_TEST_ID;
const contentDataTestSub = dataTestSub + CONTENT_TEST_ID;
@ -56,10 +58,10 @@ export const ExpandableSection: VFC<DescriptionSectionProps> = ({
);
return (
<EuiAccordion id={accordionId} buttonContent={header} initialIsOpen={expanded}>
<EuiAccordion forceState={state} onToggle={toggle} id={accordionId} buttonContent={header}>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="none" direction="column" data-test-subj={contentDataTestSub}>
{children}
{renderContent && children}
</EuiFlexGroup>
</EuiAccordion>
);

View file

@ -0,0 +1,48 @@
/*
* 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 { useReducer } from 'react';
const CLOSED = 'closed' as const;
const OPEN = 'open' as const;
type ToggleReducerState = typeof CLOSED | typeof OPEN;
const toggleReducer = (state: ToggleReducerState) => {
return state === CLOSED ? OPEN : CLOSED;
};
export interface UseAccordionStateValue {
/**
* Should children be rendered in the dom
*/
renderContent: boolean;
/**
* Use this to control the accordion visual state
*/
state: typeof CLOSED | typeof OPEN;
/**
* Handler function for cycling between the states
*/
toggle: VoidFunction;
}
/**
* Tiny hook for controlled useAccordionState
* @param expandedInitially - is accordion expanded on first render
*/
export const useAccordionState = (expandedInitially: boolean): UseAccordionStateValue => {
const initialState = expandedInitially ? OPEN : CLOSED;
const [state, toggle] = useReducer(toggleReducer, initialState);
const renderContent = state === OPEN;
return {
renderContent,
state,
toggle,
};
};