mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution][Expandable flyout] fix flyout flickering when opening/closing left panel (#210225)
## Summary We recently improved the expandable flyout by adding support for a [fully resizable flyout](https://github.com/elastic/kibana/pull/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
This commit is contained in:
parent
ed4c5d5308
commit
7a9bf1399c
3 changed files with 99 additions and 26 deletions
|
@ -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';
|
||||
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -49,7 +52,7 @@ 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);
|
||||
|
@ -57,12 +60,12 @@ export const ResizableContainer: React.FC<ResizableContainerProps> = memo(
|
|||
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(
|
||||
|
@ -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}
|
||||
>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue