[Discover] Persist histogram height to local storage (#140997)

* [Discover] Initial work to persist histogram height

* [Discover] Fix issues with persisting histogram height

* [Discover] Add tests for histogram height persistence

* [Discover] Show reset chart height button only when the layout is resizable

* [Discover] Update reset chart height button to read 'Reset to default height'
This commit is contained in:
Davis McPhee 2022-09-20 21:23:06 -03:00 committed by GitHub
parent 4c0c0db9c5
commit 0aa74edd2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 290 additions and 81 deletions

View file

@ -114,6 +114,7 @@ async function mountComponent(isTimeBased: boolean = false) {
viewMode: VIEW_MODE.DOCUMENT_LEVEL,
setDiscoverViewMode: jest.fn(),
isTimeBased,
onResetChartHeight: jest.fn(),
};
let instance: ReactWrapper = {} as ReactWrapper;

View file

@ -44,6 +44,7 @@ export function DiscoverChart({
interval,
isTimeBased,
appendHistogram,
onResetChartHeight,
}: {
className?: string;
resetSavedSearch: () => void;
@ -56,6 +57,7 @@ export function DiscoverChart({
hideChart?: boolean;
interval?: string;
appendHistogram?: ReactElement;
onResetChartHeight?: () => void;
}) {
const { data, storage } = useDiscoverServices();
const [showChartOptionsPopover, setShowChartOptionsPopover] = useState(false);
@ -113,13 +115,14 @@ export function DiscoverChart({
},
[data]
);
const panels = useChartPanels(
const panels = useChartPanels({
toggleHideChart,
(newInterval) => stateContainer.setAppState({ interval: newInterval }),
() => setShowChartOptionsPopover(false),
onChangeInterval: (newInterval) => stateContainer.setAppState({ interval: newInterval }),
closePopover: () => setShowChartOptionsPopover(false),
onResetChartHeight,
hideChart,
interval
);
interval,
});
return (
<EuiFlexGroup

View file

@ -14,20 +14,68 @@ import { EuiContextMenuPanelDescriptor } from '@elastic/eui';
describe('test useChartPanels', () => {
test('useChartsPanel when hideChart is true', async () => {
const { result } = renderHook(() => {
return useChartPanels(jest.fn(), jest.fn(), jest.fn(), true, 'auto');
return useChartPanels({
toggleHideChart: jest.fn(),
onChangeInterval: jest.fn(),
closePopover: jest.fn(),
onResetChartHeight: jest.fn(),
hideChart: true,
interval: 'auto',
});
});
const panels: EuiContextMenuPanelDescriptor[] = result.current;
const panel0: EuiContextMenuPanelDescriptor = result.current[0];
expect(panels.length).toBe(1);
expect(panel0!.items).toHaveLength(1);
expect(panel0!.items![0].icon).toBe('eye');
});
test('useChartsPanel when hideChart is false', async () => {
const { result } = renderHook(() => {
return useChartPanels(jest.fn(), jest.fn(), jest.fn(), false, 'auto');
return useChartPanels({
toggleHideChart: jest.fn(),
onChangeInterval: jest.fn(),
closePopover: jest.fn(),
onResetChartHeight: jest.fn(),
hideChart: false,
interval: 'auto',
});
});
const panels: EuiContextMenuPanelDescriptor[] = result.current;
const panel0: EuiContextMenuPanelDescriptor = result.current[0];
expect(panels.length).toBe(2);
expect(panel0!.items).toHaveLength(3);
expect(panel0!.items![0].icon).toBe('eyeClosed');
expect(panel0!.items![1].icon).toBe('refresh');
});
test('should not show reset chart height when onResetChartHeight is undefined', async () => {
const { result } = renderHook(() => {
return useChartPanels({
toggleHideChart: jest.fn(),
onChangeInterval: jest.fn(),
closePopover: jest.fn(),
hideChart: false,
interval: 'auto',
});
});
const panel0: EuiContextMenuPanelDescriptor = result.current[0];
expect(panel0!.items).toHaveLength(2);
expect(panel0!.items![0].icon).toBe('eyeClosed');
});
test('onResetChartHeight is called when the reset chart height button is clicked', async () => {
const onResetChartHeight = jest.fn();
const { result } = renderHook(() => {
return useChartPanels({
toggleHideChart: jest.fn(),
onChangeInterval: jest.fn(),
closePopover: jest.fn(),
onResetChartHeight,
hideChart: false,
interval: 'auto',
});
});
const panel0: EuiContextMenuPanelDescriptor = result.current[0];
const resetChartHeightButton = panel0!.items![1];
(resetChartHeightButton.onClick as Function)();
expect(onResetChartHeight).toBeCalled();
});
});

View file

@ -12,13 +12,21 @@ import type {
} from '@elastic/eui';
import { search } from '@kbn/data-plugin/public';
export function useChartPanels(
toggleHideChart: () => void,
onChangeInterval: (value: string) => void,
closePopover: () => void,
hideChart?: boolean,
interval?: string
) {
export function useChartPanels({
toggleHideChart,
onChangeInterval,
closePopover,
onResetChartHeight,
hideChart,
interval,
}: {
toggleHideChart: () => void;
onChangeInterval: (value: string) => void;
closePopover: () => void;
onResetChartHeight?: () => void;
hideChart?: boolean;
interval?: string;
}) {
const selectedOptionIdx = search.aggs.intervalOptions.findIndex((opt) => opt.val === interval);
const intervalDisplay =
selectedOptionIdx > -1
@ -43,6 +51,20 @@ export function useChartPanels(
},
];
if (!hideChart) {
if (onResetChartHeight) {
mainPanelItems.push({
name: i18n.translate('discover.resetChartHeight', {
defaultMessage: 'Reset to default height',
}),
icon: 'refresh',
onClick: () => {
onResetChartHeight();
closePopover();
},
'data-test-subj': 'discoverChartResetHeight',
});
}
mainPanelItems.push({
name: i18n.translate('discover.timeIntervalWithValue', {
defaultMessage: 'Time interval: {timeInterval}',

View file

@ -26,7 +26,11 @@ import { FetchStatus } from '../../../types';
import { Chart } from '../chart/point_series';
import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
import { buildDataTableRecord } from '../../../../utils/build_data_record';
import { DiscoverMainContent, DiscoverMainContentProps } from './discover_main_content';
import {
DiscoverMainContent,
DiscoverMainContentProps,
HISTOGRAM_HEIGHT_KEY,
} from './discover_main_content';
import { VIEW_MODE } from '@kbn/saved-search-plugin/public';
import { DiscoverPanels, DISCOVER_PANELS_MODE } from './discover_panels';
import { euiThemeVars } from '@kbn/ui-theme';
@ -36,21 +40,29 @@ import { setTimeout } from 'timers/promises';
import { DiscoverChart } from '../chart';
import { ReactWrapper } from 'enzyme';
import { DocumentViewModeToggle } from '../../../../components/view_mode_toggle';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { LocalStorageMock } from '../../../../__mocks__/local_storage_mock';
const mountComponent = async ({
isPlainRecord = false,
hideChart = false,
isTimeBased = true,
storage,
}: {
isPlainRecord?: boolean;
hideChart?: boolean;
isTimeBased?: boolean;
storage?: Storage;
} = {}) => {
const services = discoverServiceMock;
let services = discoverServiceMock;
services.data.query.timefilter.timefilter.getAbsoluteTime = () => {
return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' };
};
if (storage) {
services = { ...services, storage };
}
const main$ = new BehaviorSubject({
fetchStatus: FetchStatus.COMPLETE,
recordRawType: isPlainRecord ? RecordRawType.PLAIN : RecordRawType.DOCUMENT,
@ -188,67 +200,145 @@ describe('Discover main content component', () => {
window.innerWidth = windowWidth;
});
it('should set the panels mode to DISCOVER_PANELS_MODE.RESIZABLE when viewing on medium screens and above', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.m);
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.RESIZABLE);
});
describe('DISCOVER_PANELS_MODE', () => {
it('should set the panels mode to DISCOVER_PANELS_MODE.RESIZABLE when viewing on medium screens and above', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.m);
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.RESIZABLE);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED when viewing on small screens and below', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED when viewing on small screens and below', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED if hideChart is true', async () => {
const component = await mountComponent({ hideChart: true });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED if hideChart is true', async () => {
const component = await mountComponent({ hideChart: true });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED if isTimeBased is false', async () => {
const component = await mountComponent({ isTimeBased: false });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.FIXED if isTimeBased is false', async () => {
const component = await mountComponent({ isTimeBased: false });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.FIXED);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.SINGLE if isPlainRecord is true', async () => {
const component = await mountComponent({ isPlainRecord: true });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.SINGLE);
});
it('should set the panels mode to DISCOVER_PANELS_MODE.SINGLE if isPlainRecord is true', async () => {
const component = await mountComponent({ isPlainRecord: true });
expect(component.find(DiscoverPanels).prop('mode')).toBe(DISCOVER_PANELS_MODE.SINGLE);
});
it('should set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and hideChart is false', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('initialTopPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).toHaveStyle({
height: `${expectedHeight}px`,
it('should set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and hideChart is false', async () => {
const component = await mountComponent();
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('topPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).toHaveStyle({
height: `${expectedHeight}px`,
});
});
it('should not set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and hideChart is true', async () => {
const component = await mountComponent({ hideChart: true });
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('topPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).not.toHaveStyle({
height: `${expectedHeight}px`,
});
});
it('should not set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and isTimeBased is false', async () => {
const component = await mountComponent({ isTimeBased: false });
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('topPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).not.toHaveStyle({
height: `${expectedHeight}px`,
});
});
it('should pass undefined for onResetChartHeight to DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED', async () => {
const component = await mountComponent();
expect(component.find(DiscoverChart).prop('onResetChartHeight')).toBeDefined();
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
expect(component.find(DiscoverChart).prop('onResetChartHeight')).toBeUndefined();
});
});
it('should not set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and hideChart is true', async () => {
const component = await mountComponent({ hideChart: true });
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('initialTopPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).not.toHaveStyle({
height: `${expectedHeight}px`,
describe('DocumentViewModeToggle', () => {
it('should show DocumentViewModeToggle when isPlainRecord is false', async () => {
const component = await mountComponent();
expect(component.find(DocumentViewModeToggle).exists()).toBe(true);
});
it('should not show DocumentViewModeToggle when isPlainRecord is true', async () => {
const component = await mountComponent({ isPlainRecord: true });
expect(component.find(DocumentViewModeToggle).exists()).toBe(false);
});
});
it('should not set a fixed height for DiscoverChart when panels mode is DISCOVER_PANELS_MODE.FIXED and isTimeBased is false', async () => {
const component = await mountComponent({ isTimeBased: false });
setWindowWidth(component, euiThemeVars.euiBreakpoints.s);
const expectedHeight = component.find(DiscoverPanels).prop('initialTopPanelHeight');
expect(component.find(DiscoverChart).childAt(0).getDOMNode()).not.toHaveStyle({
height: `${expectedHeight}px`,
describe('topPanelHeight persistence', () => {
it('should try to get the initial topPanelHeight for DiscoverPanels from storage', async () => {
const storage = new LocalStorageMock({}) as unknown as Storage;
const originalGet = storage.get;
storage.get = jest.fn().mockImplementation(originalGet);
await mountComponent({ storage });
expect(storage.get).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY);
});
});
it('should show DocumentViewModeToggle when isPlainRecord is false', async () => {
const component = await mountComponent();
expect(component.find(DocumentViewModeToggle).exists()).toBe(true);
});
it('should pass a default topPanelHeight to DiscoverPanels if no value is found in storage', async () => {
const storage = new LocalStorageMock({}) as unknown as Storage;
const originalGet = storage.get;
storage.get = jest.fn().mockImplementation(originalGet);
const component = await mountComponent({ storage });
expect(storage.get).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY);
expect(storage.get).toHaveReturnedWith(null);
expect(component.find(DiscoverPanels).prop('topPanelHeight')).toBeGreaterThan(0);
});
it('should not show DocumentViewModeToggle when isPlainRecord is true', async () => {
const component = await mountComponent({ isPlainRecord: true });
expect(component.find(DocumentViewModeToggle).exists()).toBe(false);
it('should pass the stored topPanelHeight to DiscoverPanels if a value is found in storage', async () => {
const storage = new LocalStorageMock({}) as unknown as Storage;
const topPanelHeight = 123;
storage.get = jest.fn().mockImplementation(() => topPanelHeight);
const component = await mountComponent({ storage });
expect(storage.get).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY);
expect(storage.get).toHaveReturnedWith(topPanelHeight);
expect(component.find(DiscoverPanels).prop('topPanelHeight')).toBe(topPanelHeight);
});
it('should update the topPanelHeight in storage and pass the new value to DiscoverPanels when the topPanelHeight changes', async () => {
const storage = new LocalStorageMock({}) as unknown as Storage;
const originalSet = storage.set;
storage.set = jest.fn().mockImplementation(originalSet);
const component = await mountComponent({ storage });
const newTopPanelHeight = 123;
expect(component.find(DiscoverPanels).prop('topPanelHeight')).not.toBe(newTopPanelHeight);
act(() => {
component.find(DiscoverPanels).prop('onTopPanelHeightChange')(newTopPanelHeight);
});
component.update();
expect(storage.set).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY, newTopPanelHeight);
expect(component.find(DiscoverPanels).prop('topPanelHeight')).toBe(newTopPanelHeight);
});
it('should reset the topPanelHeight to the default when onResetChartHeight is called on DiscoverChart', async () => {
const storage = new LocalStorageMock({}) as unknown as Storage;
const originalSet = storage.set;
storage.set = jest.fn().mockImplementation(originalSet);
const component = await mountComponent({ storage });
const defaultTopPanelHeight = component.find(DiscoverPanels).prop('topPanelHeight');
const newTopPanelHeight = 123;
expect(component.find(DiscoverPanels).prop('topPanelHeight')).not.toBe(newTopPanelHeight);
act(() => {
component.find(DiscoverPanels).prop('onTopPanelHeightChange')(newTopPanelHeight);
});
component.update();
expect(storage.set).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY, newTopPanelHeight);
expect(component.find(DiscoverPanels).prop('topPanelHeight')).toBe(newTopPanelHeight);
act(() => {
component.find(DiscoverChart).prop('onResetChartHeight')!();
});
component.update();
expect(storage.set).toHaveBeenCalledWith(HISTOGRAM_HEIGHT_KEY, defaultTopPanelHeight);
expect(component.find(DiscoverPanels).prop('topPanelHeight')).toBe(defaultTopPanelHeight);
});
});
});

View file

@ -15,7 +15,7 @@ import {
useIsWithinBreakpoints,
} from '@elastic/eui';
import { SavedSearch } from '@kbn/saved-search-plugin/public';
import React, { RefObject, useCallback, useMemo } from 'react';
import React, { RefObject, useCallback, useMemo, useState } from 'react';
import { DataView } from '@kbn/data-views-plugin/common';
import { METRIC_TYPE } from '@kbn/analytics';
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
@ -35,6 +35,8 @@ import { DiscoverPanels, DISCOVER_PANELS_MODE } from './discover_panels';
const DiscoverChartMemoized = React.memo(DiscoverChart);
const FieldStatisticsTableMemoized = React.memo(FieldStatisticsTable);
export const HISTOGRAM_HEIGHT_KEY = 'discover:histogramHeight';
export interface DiscoverMainContentProps {
isPlainRecord: boolean;
dataView: DataView;
@ -74,7 +76,7 @@ export const DiscoverMainContent = ({
columns,
resizeRef,
}: DiscoverMainContentProps) => {
const { trackUiMetric } = useDiscoverServices();
const { trackUiMetric, storage } = useDiscoverServices();
const setDiscoverViewMode = useCallback(
(mode: VIEW_MODE) => {
@ -104,14 +106,36 @@ export const DiscoverMainContent = ({
const hideChart = state.hideChart || !isTimeBased;
const showFixedPanels = useIsWithinBreakpoints(['xs', 's']) || isPlainRecord || hideChart;
const { euiTheme } = useEuiTheme();
const topPanelHeight = euiTheme.base * 12;
const defaultTopPanelHeight = euiTheme.base * 12;
const minTopPanelHeight = euiTheme.base * 8;
const minMainPanelHeight = euiTheme.base * 10;
const [topPanelHeight, setTopPanelHeight] = useState(
Number(storage.get(HISTOGRAM_HEIGHT_KEY)) || defaultTopPanelHeight
);
const storeTopPanelHeight = useCallback(
(newTopPanelHeight: number) => {
storage.set(HISTOGRAM_HEIGHT_KEY, newTopPanelHeight);
setTopPanelHeight(newTopPanelHeight);
},
[storage]
);
const resetTopPanelHeight = useCallback(
() => storeTopPanelHeight(defaultTopPanelHeight),
[storeTopPanelHeight, defaultTopPanelHeight]
);
const onTopPanelHeightChange = useCallback(
(newTopPanelHeight: number) => storeTopPanelHeight(newTopPanelHeight),
[storeTopPanelHeight]
);
const chartClassName =
showFixedPanels && !hideChart
? css`
height: ${topPanelHeight}px;
height: ${defaultTopPanelHeight}px;
`
: 'eui-fullHeight';
@ -136,6 +160,9 @@ export const DiscoverMainContent = ({
interval={state.interval}
isTimeBased={isTimeBased}
appendHistogram={showFixedPanels ? <EuiSpacer size="s" /> : <EuiSpacer size="m" />}
onResetChartHeight={
panelsMode === DISCOVER_PANELS_MODE.RESIZABLE ? resetTopPanelHeight : undefined
}
/>
</InPortal>
<InPortal node={mainPanelNode}>
@ -189,11 +216,12 @@ export const DiscoverMainContent = ({
className="dscPageContent__inner"
mode={panelsMode}
resizeRef={resizeRef}
initialTopPanelHeight={topPanelHeight}
topPanelHeight={topPanelHeight}
minTopPanelHeight={minTopPanelHeight}
minMainPanelHeight={minMainPanelHeight}
topPanel={<OutPortal node={topPanelNode} />}
mainPanel={<OutPortal node={mainPanelNode} />}
onTopPanelHeightChange={onTopPanelHeightChange}
/>
</>
);

View file

@ -34,11 +34,12 @@ describe('Discover panels component', () => {
<DiscoverPanels
mode={mode}
resizeRef={resizeRef}
initialTopPanelHeight={initialTopPanelHeight}
topPanelHeight={initialTopPanelHeight}
minTopPanelHeight={minTopPanelHeight}
minMainPanelHeight={minMainPanelHeight}
topPanel={topPanel}
mainPanel={mainPanel}
onTopPanelHeightChange={jest.fn()}
/>
);
};

View file

@ -20,11 +20,12 @@ export interface DiscoverPanelsProps {
className?: string;
mode: DISCOVER_PANELS_MODE;
resizeRef: RefObject<HTMLDivElement>;
initialTopPanelHeight: number;
topPanelHeight: number;
minTopPanelHeight: number;
minMainPanelHeight: number;
topPanel: ReactElement;
mainPanel: ReactElement;
onTopPanelHeightChange: (height: number) => void;
}
const fixedModes = [DISCOVER_PANELS_MODE.SINGLE, DISCOVER_PANELS_MODE.FIXED];
@ -33,11 +34,12 @@ export const DiscoverPanels = ({
className,
mode,
resizeRef,
initialTopPanelHeight,
topPanelHeight,
minTopPanelHeight,
minMainPanelHeight,
topPanel,
mainPanel,
onTopPanelHeightChange,
}: DiscoverPanelsProps) => {
const panelsProps = { className, topPanel, mainPanel };
@ -46,9 +48,10 @@ export const DiscoverPanels = ({
) : (
<DiscoverPanelsResizable
resizeRef={resizeRef}
initialTopPanelHeight={initialTopPanelHeight}
topPanelHeight={topPanelHeight}
minTopPanelHeight={minTopPanelHeight}
minMainPanelHeight={minMainPanelHeight}
onTopPanelHeightChange={onTopPanelHeightChange}
{...panelsProps}
/>
);

View file

@ -33,6 +33,7 @@ describe('Discover panels resizable', () => {
topPanel = <></>,
mainPanel = <></>,
attachTo,
onTopPanelHeightChange = jest.fn(),
}: {
className?: string;
resizeRef?: RefObject<HTMLDivElement>;
@ -42,16 +43,18 @@ describe('Discover panels resizable', () => {
topPanel?: ReactElement;
mainPanel?: ReactElement;
attachTo?: HTMLElement;
onTopPanelHeightChange?: (height: number) => void;
}) => {
return mount(
<DiscoverPanelsResizable
className={className}
resizeRef={resizeRef}
initialTopPanelHeight={initialTopPanelHeight}
topPanelHeight={initialTopPanelHeight}
minTopPanelHeight={minTopPanelHeight}
minMainPanelHeight={minMainPanelHeight}
topPanel={topPanel}
mainPanel={mainPanel}
onTopPanelHeightChange={onTopPanelHeightChange}
/>,
attachTo ? { attachTo } : undefined
);
@ -95,7 +98,10 @@ describe('Discover panels resizable', () => {
it('should set the correct heights of both panels when the panels are resized', () => {
const initialTopPanelHeight = 200;
const component = mountComponent({ initialTopPanelHeight });
const onTopPanelHeightChange = jest.fn((topPanelHeight) => {
component.setProps({ topPanelHeight }).update();
});
const component = mountComponent({ initialTopPanelHeight, onTopPanelHeightChange });
expectCorrectPanelSizes(component, containerHeight, initialTopPanelHeight);
const newTopPanelSize = 30;
const onPanelSizeChange = component
@ -106,7 +112,9 @@ describe('Discover panels resizable', () => {
onPanelSizeChange({ [topPanelId]: newTopPanelSize });
});
forceRender(component);
expectCorrectPanelSizes(component, containerHeight, containerHeight * (newTopPanelSize / 100));
const newTopPanelHeight = (newTopPanelSize / 100) * containerHeight;
expect(onTopPanelHeightChange).toHaveBeenCalledWith(newTopPanelHeight);
expectCorrectPanelSizes(component, containerHeight, newTopPanelHeight);
});
it('should maintain the height of the top panel and resize the main panel when the container height changes', () => {

View file

@ -19,23 +19,24 @@ const pixelsToPercent = (containerHeight: number, pixels: number) =>
export const DiscoverPanelsResizable = ({
className,
resizeRef,
initialTopPanelHeight,
topPanelHeight,
minTopPanelHeight,
minMainPanelHeight,
topPanel,
mainPanel,
onTopPanelHeightChange,
}: {
className?: string;
resizeRef: RefObject<HTMLDivElement>;
initialTopPanelHeight: number;
topPanelHeight: number;
minTopPanelHeight: number;
minMainPanelHeight: number;
topPanel: ReactElement;
mainPanel: ReactElement;
onTopPanelHeightChange: (height: number) => void;
}) => {
const topPanelId = useGeneratedHtmlId({ prefix: 'topPanel' });
const { height: containerHeight } = useResizeObserver(resizeRef.current);
const [topPanelHeight, setTopPanelHeight] = useState(initialTopPanelHeight);
const [panelSizes, setPanelSizes] = useState({ topPanelSize: 0, mainPanelSize: 0 });
// EuiResizableContainer doesn't work properly when used with react-reverse-portal and
@ -69,9 +70,13 @@ export const DiscoverPanelsResizable = ({
// the effect below to update the panel sizes.
const onPanelSizeChange = useCallback(
({ [topPanelId]: topPanelSize }: { [key: string]: number }) => {
setTopPanelHeight(percentToPixels(containerHeight, topPanelSize));
const newTopPanelHeight = percentToPixels(containerHeight, topPanelSize);
if (newTopPanelHeight !== topPanelHeight) {
onTopPanelHeightChange(newTopPanelHeight);
}
},
[containerHeight, topPanelId]
[containerHeight, onTopPanelHeightChange, topPanelHeight, topPanelId]
);
// This effect will update the panel sizes based on the top panel height whenever