Skip to content

Commit

Permalink
[Security Solution][Expandable flyout] fix flyout flickering when ope…
Browse files Browse the repository at this point in the history
…ning/closing left panel (elastic#210225)

## Summary

We recently improved the expandable flyout by adding support for a
[fully resizable flyout](elastic#192906).
This work introduce a minor inconvenience, where the right panel gets
re-rendered every time the user expands or collapses the flyout.

This PR fixes this issue by better using the EUI resizable container
(see how to externally control a resizable container
[here](https://eui.elastic.co/#/layout/resizable-container#collapsible-panels-with-external-control)).
The flyout is now always showing a resizable container (even in
collapsed mode) but EUI manages internally hiding the left section and
the resize button.

#### Old behavior


https://github.com/user-attachments/assets/4d7589ec-0edf-4690-9ce4-7b969ae0bb44

#### New behavior


https://github.com/user-attachments/assets/7cf720b8-5b31-4cc9-b213-21472ea880d6

The rest of the flyout's behavior remains untouched:
- identical default widths
- user selected widths are still applied
- no changes to the preview behavior

### Checklist

- [ ] [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
  • Loading branch information
PhilippeOberti authored Feb 7, 2025
1 parent ed4c5d5 commit 7a9bf13
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
useDispatch,
useSelector,
} from '../store/redux';
import { RightSection } from './right_section';
import { useSections } from '../hooks/use_sections';
import { useExpandableFlyoutState } from '../hooks/use_expandable_flyout_state';
import { useExpandableFlyoutApi } from '../hooks/use_expandable_flyout_api';
Expand Down Expand Up @@ -215,15 +214,12 @@ export const Container: React.FC<ContainerProps> = memo(
onResize={onResize}
minWidth={minFlyoutWidth}
>
{showCollapsed && <RightSection component={rightComponent as React.ReactElement} />}

{showExpanded && (
<ResizableContainer
leftComponent={leftComponent as React.ReactElement}
rightComponent={rightComponent as React.ReactElement}
showPreview={showPreview}
/>
)}
<ResizableContainer
leftComponent={leftComponent as React.ReactElement}
rightComponent={rightComponent as React.ReactElement}
showLeft={showExpanded}
showPreview={showPreview}
/>

{showPreview && (
<PreviewSection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const leftComponent = <div>{'left component'}</div>;
const rightComponent = <div>{'right component'}</div>;

describe('ResizableContainer', () => {
it('should render left and right component as well as resize button', () => {
it('should render right section only', () => {
const state = {
...initialState,
ui: {
Expand All @@ -37,13 +37,86 @@ describe('ResizableContainer', () => {
<ResizableContainer
leftComponent={leftComponent}
rightComponent={rightComponent}
showLeft={false}
showPreview={false}
/>
</TestProvider>
);

expect(getByTestId(RESIZABLE_LEFT_SECTION_TEST_ID)).toBeInTheDocument();
expect(getByTestId(RESIZABLE_BUTTON_TEST_ID)).toBeInTheDocument();
expect(getByTestId(RESIZABLE_RIGHT_SECTION_TEST_ID)).toBeInTheDocument();
const rightSection = getByTestId(RESIZABLE_RIGHT_SECTION_TEST_ID);
expect(rightSection).toBeInTheDocument();
expect(rightSection.parentElement).toHaveStyle('inline-size: 100%; block-size: auto;');

const resizeButton = getByTestId(RESIZABLE_BUTTON_TEST_ID);
expect(resizeButton).toBeInTheDocument();
expect(resizeButton).toBeDisabled();

const leftSection = getByTestId(RESIZABLE_LEFT_SECTION_TEST_ID);
expect(leftSection).toBeInTheDocument();
expect(leftSection.parentElement).toHaveStyle('inline-size: 0%; block-size: auto;');
});

it('should render left and right components with resize button enabled', () => {
const state = {
...initialState,
ui: {
...initialState.ui,
userSectionWidths: {
leftPercentage: 50,
rightPercentage: 50,
},
},
};

const { getByTestId } = render(
<TestProvider state={state}>
<ResizableContainer
leftComponent={leftComponent}
rightComponent={rightComponent}
showLeft={true}
showPreview={false}
/>
</TestProvider>
);

const rightSection = getByTestId(RESIZABLE_RIGHT_SECTION_TEST_ID);
expect(rightSection).toBeInTheDocument();
expect(rightSection.parentElement).toHaveStyle('inline-size: 50%; block-size: auto;');

const resizeButton = getByTestId(RESIZABLE_BUTTON_TEST_ID);
expect(resizeButton).toBeInTheDocument();
expect(resizeButton).not.toBeDisabled();

const leftSection = getByTestId(RESIZABLE_LEFT_SECTION_TEST_ID);
expect(leftSection).toBeInTheDocument();
expect(leftSection.parentElement).toHaveStyle('inline-size: 50%; block-size: auto;');
});

it('should disable the resize button if preview is rendered', () => {
const state = {
...initialState,
ui: {
...initialState.ui,
userSectionWidths: {
leftPercentage: 50,
rightPercentage: 50,
},
},
};

const { getByTestId } = render(
<TestProvider state={state}>
<ResizableContainer
leftComponent={leftComponent}
rightComponent={rightComponent}
showLeft={true}
showPreview={true}
/>
</TestProvider>
);

const resizeButton = getByTestId(RESIZABLE_BUTTON_TEST_ID);
expect(resizeButton).toBeInTheDocument();
expect(resizeButton).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import {
import { LeftSection } from './left_section';
import { RightSection } from './right_section';

const RIGHT_SECTION_MIN_WIDTH = '380px';
const LEFT_SECTION_MIN_WIDTH = '380px';
const MIN_SECTION_WIDTH = '380px';
const LEFT_PANEL_ID = 'left';
const RIGHT_PANEL_ID = 'right';

Expand All @@ -38,6 +37,10 @@ interface ResizableContainerProps {
* The component to render on the right side of the flyout
*/
rightComponent: React.ReactElement;
/**
* If the left section is not shown we disable the resize button and hide the left size of the resizable panel
*/
showLeft: boolean;
/**
* If the preview section is shown we disable the resize button
*/
Expand All @@ -49,20 +52,20 @@ interface ResizableContainerProps {
* It allows the resizing of the sections, saving the percentages in local storage.
*/
export const ResizableContainer: React.FC<ResizableContainerProps> = memo(
({ leftComponent, rightComponent, showPreview }: ResizableContainerProps) => {
({ leftComponent, rightComponent, showLeft, showPreview }: ResizableContainerProps) => {
const dispatch = useDispatch();

const { leftPercentage, rightPercentage } = useSelector(selectUserSectionWidths);
const type = useSelector(selectPushVsOverlay);
const defaultPercentages = useSelector(selectDefaultWidths);

const initialLeftPercentage = useMemo(
() => leftPercentage || defaultPercentages[type].leftPercentage,
[defaultPercentages, leftPercentage, type]
() => (showLeft ? leftPercentage || defaultPercentages[type].leftPercentage : 0),
[defaultPercentages, leftPercentage, showLeft, type]
);
const initialRightPercentage = useMemo(
() => rightPercentage || defaultPercentages[type].rightPercentage,
[defaultPercentages, rightPercentage, type]
() => (showLeft ? rightPercentage || defaultPercentages[type].rightPercentage : 100),
[defaultPercentages, rightPercentage, showLeft, type]
);

const onWidthChange = useCallback(
Expand All @@ -88,19 +91,20 @@ export const ResizableContainer: React.FC<ResizableContainerProps> = memo(
<EuiResizablePanel
id={LEFT_PANEL_ID}
initialSize={initialLeftPercentage}
size={leftPercentage}
minSize={LEFT_SECTION_MIN_WIDTH}
paddingSize="none"
minSize={MIN_SECTION_WIDTH}
data-test-subj={RESIZABLE_LEFT_SECTION_TEST_ID}
>
<LeftSection component={leftComponent} />
</EuiResizablePanel>
<EuiResizableButton disabled={showPreview} data-test-subj={RESIZABLE_BUTTON_TEST_ID} />
<EuiResizableButton
disabled={showPreview || !showLeft}
data-test-subj={RESIZABLE_BUTTON_TEST_ID}
/>
<EuiResizablePanel
id={RIGHT_PANEL_ID}
initialSize={initialRightPercentage}
size={rightPercentage}
minSize={RIGHT_SECTION_MIN_WIDTH}
minSize={MIN_SECTION_WIDTH}
paddingSize="none"
data-test-subj={RESIZABLE_RIGHT_SECTION_TEST_ID}
>
Expand Down

0 comments on commit 7a9bf13

Please sign in to comment.