Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lens] Data panel styling and optimizations #40787

Merged
merged 103 commits into from
Jul 17, 2019
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
f46855e
[lens] Dimension panel lets users select operations and fields indivi…
wylieconlon May 30, 2019
dcde41d
Merge remote-tracking branch 'origin/feature/lens' into lens/aggregat…
wylieconlon May 31, 2019
4a3ea3f
Merge remote-tracking branch 'origin/master' into lens/aggregations
wylieconlon Jun 3, 2019
30f69e3
Split files and add tests
wylieconlon Jun 3, 2019
82e2865
Merge remote-tracking branch 'origin/feature/lens' into lens/aggregat…
wylieconlon Jun 3, 2019
fe4238a
Fix dimension labeling and add clear button
wylieconlon Jun 4, 2019
4d09416
Support more aggregations, aggregation nesting, rollups, and clearing
wylieconlon Jun 5, 2019
6f81ded
Merge remote-tracking branch 'origin/feature/lens' into lens/aggregat…
wylieconlon Jun 5, 2019
3bf54d4
Fix esaggs expression
wylieconlon Jun 5, 2019
241187b
Merge remote-tracking branch 'origin/feature/lens' into lens/aggregat…
wylieconlon Jun 6, 2019
8c50598
Increase top-level test coverage of dimension panel
wylieconlon Jun 6, 2019
063715c
Merge branch 'feature/lens' into lens/aggregations
flash1293 Jun 7, 2019
8359b28
start work on param editors for operations
flash1293 Jun 7, 2019
6a3e6f8
add params for terms
flash1293 Jun 7, 2019
9cb80a8
remove unused variable
flash1293 Jun 7, 2019
4718369
Merge branch 'feature/lens' into lens/agg-configs
flash1293 Jun 11, 2019
5510db0
refactor operations
flash1293 Jun 11, 2019
404944f
move esaggs configurations to individual operation files
flash1293 Jun 11, 2019
8e0dc86
implement new edit flow
flash1293 Jun 12, 2019
520f0e7
split up dimension panel code
flash1293 Jun 12, 2019
7d6f3c9
Merge branch 'feature/lens' into lens/agg-configs
flash1293 Jun 12, 2019
cdcc822
fix some tests
flash1293 Jun 13, 2019
3e7c3b4
Merge branch 'feature/lens' into lens/agg-configs
flash1293 Jun 13, 2019
b72998d
moved stuff around and started cleaning up and adding tests
flash1293 Jun 13, 2019
41eb4d4
fix tests for dimension panel
flash1293 Jun 13, 2019
0674c2c
fix tests
flash1293 Jun 13, 2019
6d420e6
add tests and i18n
flash1293 Jun 13, 2019
2f54558
added a few more tests
flash1293 Jun 13, 2019
d3e356c
add test subj
flash1293 Jun 13, 2019
a1f55cf
remove unused import
flash1293 Jun 13, 2019
60c0239
start work on operation switching
flash1293 Jun 14, 2019
4511c81
highlight currently active operation
flash1293 Jun 14, 2019
5183115
Merge branch 'feature/lens' into lens/popover-configs
flash1293 Jun 19, 2019
6d91f2e
Auto format
flash1293 Jun 19, 2019
2cdc322
adjust user flow as discussed
flash1293 Jun 19, 2019
aa3c8fd
Merge branch 'feature/lens' into lens/popover-configs
flash1293 Jun 24, 2019
1ae848f
resolve merge conflicts
flash1293 Jun 24, 2019
09328ad
fix styling and add label behavior
flash1293 Jun 24, 2019
82b7ce4
start fixing tests and things
flash1293 Jun 24, 2019
df18560
fix css issues
flash1293 Jun 25, 2019
78f45c5
fix existing dimension panel test
flash1293 Jun 25, 2019
f82a200
add tests
flash1293 Jun 25, 2019
2798552
condense tests
flash1293 Jun 25, 2019
486bae9
rename stuff and carry over params when switching columns if possible
flash1293 Jun 25, 2019
c2b00cf
add basic layout
flash1293 Jun 25, 2019
754b29f
fix basic styling issues
flash1293 Jun 25, 2019
b87f18e
fix tests
flash1293 Jun 25, 2019
3be4f8e
starting to implement data panel
flash1293 Jun 25, 2019
ed3cf75
remove unused import
flash1293 Jun 25, 2019
6c6d037
Merge branch 'lens/styling' into lens/data-panel-styling
flash1293 Jun 25, 2019
46f594a
Merge branch 'feature/lens' into lens/popover-configs
flash1293 Jun 26, 2019
2690790
PR review fixes
flash1293 Jun 26, 2019
bbf573b
Merge branch 'feature/lens' into lens/popover-configs
flash1293 Jun 26, 2019
2634b9d
Merge branch 'feature/lens' into lens/styling
flash1293 Jun 26, 2019
0dcc1f4
PR review fixes
flash1293 Jun 26, 2019
baba0ef
Merge branch 'lens/styling' into lens/data-panel-styling
flash1293 Jun 26, 2019
e10488d
remove important marker
flash1293 Jun 26, 2019
68d50ca
size right side bar correctly
flash1293 Jun 26, 2019
6137613
Merge branch 'lens/styling' into lens/data-panel-styling
flash1293 Jun 26, 2019
1536038
multi line labels and type filter
flash1293 Jun 26, 2019
c4947bc
review fixes
flash1293 Jun 27, 2019
084cd26
Merge branch 'feature/lens' into lens/popover-configs
flash1293 Jun 27, 2019
d89743b
Merge branch 'feature/lens' into lens/styling
flash1293 Jun 27, 2019
de52e8b
Merge branch 'lens/styling' into lens/data-panel-styling
flash1293 Jun 27, 2019
34fe345
Merge branch 'lens/popover-configs' into lens/data-panel-styling
flash1293 Jun 27, 2019
08afe00
add tests
flash1293 Jun 27, 2019
094fa73
Merge branch 'feature/lens' into lens/styling
flash1293 Jun 27, 2019
6c7ab30
Merge branch 'lens/styling' into lens/data-panel-styling
flash1293 Jun 27, 2019
0c54840
fix small stuff
flash1293 Jun 27, 2019
fcd2ff4
solve i18n bug
flash1293 Jun 27, 2019
6449718
Merge branch 'feature/lens' into lens/data-panel-styling
flash1293 Jun 28, 2019
4561870
fix test
flash1293 Jun 28, 2019
38c1ce5
Merge branch 'feature/lens' into lens/data-panel-styling
flash1293 Jul 1, 2019
aced115
Merge branch 'lens/data-panel-styling' of https://github.com/flash129…
chrisdavies Jul 1, 2019
38cd6b2
Optimizations for larger index patterns
chrisdavies Jul 8, 2019
2140f2e
Merge upstream
chrisdavies Jul 8, 2019
0b82a6c
Fix TypeScript and linter errors
chrisdavies Jul 8, 2019
2425799
Fix I18n import
chrisdavies Jul 8, 2019
da9ea15
Fix dynamic scrolling in Firefox
chrisdavies Jul 8, 2019
26e5a0e
Merge branch 'feature/lens' of github.com:elastic/kibana into lens/da…
chrisdavies Jul 10, 2019
d0824f6
Make component debouncing general purpose
chrisdavies Jul 10, 2019
35a644b
Make horizontal bar charts render properly
chrisdavies Jul 10, 2019
6aa0f03
Merge branch 'feature/lens' of github.com:elastic/kibana into lens/da…
chrisdavies Jul 10, 2019
c10378e
Fix broken tests
chrisdavies Jul 10, 2019
b1792a4
Add basic tests for debounced component
chrisdavies Jul 10, 2019
2008051
Fix Firefox scroll issue
chrisdavies Jul 10, 2019
cd105d9
Merge upstream
chrisdavies Jul 11, 2019
57b0ff2
Fix typescript errors
chrisdavies Jul 11, 2019
f936629
Fix merge issue
chrisdavies Jul 11, 2019
eec45aa
Tweaks based on PR feedback
chrisdavies Jul 11, 2019
a4b5325
Fix styling in Safari
chrisdavies Jul 11, 2019
dddf92f
Tweak debounced component variable names, comments
chrisdavies Jul 11, 2019
6aa2e0e
Add localization to data panel wrapper
chrisdavies Jul 11, 2019
6366cf4
Add rudimentary smokescreen test for FieldIcon
chrisdavies Jul 11, 2019
e9ad95f
Merge upstream
chrisdavies Jul 15, 2019
80afe61
Clear data panel filters on index pattern change
chrisdavies Jul 15, 2019
fd9a0a5
Add test of drag drop provider memoization
chrisdavies Jul 16, 2019
df1cab5
Merge branch 'feature/lens' of github.com:elastic/kibana into lens/da…
chrisdavies Jul 16, 2019
770e2a7
Merge branch 'feature/lens' of github.com:elastic/kibana into lens/da…
chrisdavies Jul 16, 2019
b130c56
Merge branch 'lens/data-panel-styling' of github.com:chrisdavies/kiba…
chrisdavies Jul 16, 2019
bdbff66
Merge branch 'feature/lens' of github.com:elastic/kibana into lens/da…
chrisdavies Jul 16, 2019
5fd04d0
Tweak RootDragDropProvider test
chrisdavies Jul 16, 2019
41a6ebc
Fix indexpattern.scss
chrisdavies Jul 17, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
import { debouncedComponent } from './debounced_component';

describe('debouncedComponent', () => {
test('immediately renders', () => {
const TestComponent = debouncedComponent(({ title }: { title: string }) => {
return <h1>{title}</h1>;
});
expect(mount(<TestComponent title="hoi" />).html()).toMatchInlineSnapshot(`"<h1>hoi</h1>"`);
});

test('debounces changes', async () => {
const TestComponent = debouncedComponent(({ title }: { title: string }) => {
return <h1>{title}</h1>;
}, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm skeptical of any tests using real timers, even if this is effectively immediate. I would recommend using jest.useFakeTimers(): https://jestjs.io/docs/en/timer-mocks

Copy link
Contributor Author

@chrisdavies chrisdavies Jul 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When possible, I prefer to use the real thing, but I'm not strongly opinionated on this.

Edit: Doesn't seem to work, due to the internals of debounce.

const component = mount(<TestComponent title="there" />);
component.setProps({ title: 'yall' });
expect(component.html()).toMatchInlineSnapshot(`"<h1>there</h1>"`);
await new Promise(r => setTimeout(r, 1));
expect(component.html()).toMatchInlineSnapshot(`"<h1>yall</h1>"`);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These snapshot tests are really weak- please assert something specific about the content, such as:

expect(mount(...).first().type()).toEqual('h1');
...
expect(mount(...).text()).toEqual('yall');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the snapshot to be more effective than the examples you gave. Maybe we can discuss.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I say they're weak is that snapshots aren't testing the behavior of the system. If I change the behavior here, I want tests to fail. Instead of tests failing with a specific message, it says that the snapshots have changed and I see a diff that I have to interpret myself. There's no assertion of specific behavior.

For example, the issue with the SeriesType in the XY chart was made worse by snapshot testing. We were snapshotting the rendered chart, but without any assertions that the right series was rendered. So until I fixed it, we were rendering the horizontal_bar chart as a vertical area chart.

My preferred solution is combination, like I did for the SeriesType issue:

    test('it renders stacked horizontal bar', () => {
      const { data, args } = sampleArgs();

      const component = shallow(
        <XYChart data={data} args={{ ...args, seriesType: 'horizontal_bar_stacked' }} />
      );
      expect(component).toMatchSnapshot();
      expect(component.find(BarSeries)).toHaveLength(1);
      expect(component.find(BarSeries).prop('stackAccessors')).toHaveLength(1);
      expect(component.find(Settings).prop('rotation')).toEqual(90);
});

That kind of test will catch both unexpected additions and fail fast if the required behavior changes.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState, useMemo, memo, FunctionComponent } from 'react';
import { debounce } from 'lodash';

export function debouncedComponent<TProps>(component: FunctionComponent<TProps>, delay = 256) {
const MemoizedComponent = (memo(component) as unknown) as FunctionComponent<TProps>;

return memo((props: TProps) => {
const [rendered, setRendered] = useState(props);
const delayRender = useMemo(() => debounce(setRendered, delay), []);

delayRender(props);

return React.createElement(MemoizedComponent, rendered);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't reading this correctly the first time around, it seems like rendered is not a boolean but it's actually representing the props argument... but memoized again?. I'm confused about the double-memoization happening here. There's something about the control flow here that isn't coming across to me with these variable names. Can you clarify the names?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Good point. Rendered is a terrible name.

});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './debounced_component';
7 changes: 4 additions & 3 deletions x-pack/legacy/plugins/lens/public/drag_drop/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';

/**
* The shape of the drag / drop context.
Expand Down Expand Up @@ -64,7 +64,7 @@ export function RootDragDropProvider({ children }: { children: React.ReactNode }
const [state, setState] = useState<{ dragging: unknown }>({
dragging: undefined,
});
const setDragging = (dragging: unknown) => setState({ dragging });
const setDragging = useMemo(() => (dragging: unknown) => setState({ dragging }), [setState]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to have a test for the equality of the dragging property during a continuous drag so we don't accidentally break this optimization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:

expect(component1.prop('setDragging')).toEqual(component2.prop('setDragging'))


return (
<ChildDragDropProvider dragging={state.dragging} setDragging={setDragging}>
Expand All @@ -81,5 +81,6 @@ export function RootDragDropProvider({ children }: { children: React.ReactNode }
* @param props
*/
export function ChildDragDropProvider({ dragging, setDragging, children }: ProviderProps) {
return <DragContext.Provider value={{ dragging, setDragging }}>{children}</DragContext.Provider>;
const value = useMemo(() => ({ dragging, setDragging }), [setDragging, dragging]);
return <DragContext.Provider value={value}>{children}</DragContext.Provider>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useMemo, useContext } from 'react';
import React, { useMemo, useContext, memo } from 'react';
import { EuiSelect } from '@elastic/eui';
import { NativeRenderer } from '../../native_renderer';
import { Action } from './state_management';
Expand Down Expand Up @@ -43,7 +43,7 @@ function getSuggestedVisualizationState(
return visualization.initialize(datasource, suggestions[0].state);
}

export function ConfigPanelWrapper(props: ConfigPanelWrapperProps) {
export const ConfigPanelWrapper = memo(function ConfigPanelWrapper(props: ConfigPanelWrapperProps) {
const context = useContext(DragContext);
const setVisualizationState = useMemo(
() => (newState: unknown) => {
Expand Down Expand Up @@ -89,4 +89,4 @@ export function ConfigPanelWrapper(props: ConfigPanelWrapperProps) {
)}
</>
);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useMemo, memo, useContext } from 'react';
import { EuiSelect } from '@elastic/eui';
import React, { useMemo, memo, useContext, useState } from 'react';
import { EuiPopover, EuiButtonIcon, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty hard to test this out since we only have one data source for now! It's maybe not worth optimizing for switching data sources?

import { DatasourceDataPanelProps, Datasource } from '../../../public';
import { NativeRenderer } from '../../native_renderer';
import { Action } from './state_management';
Expand Down Expand Up @@ -36,21 +36,52 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => {
setState: setDatasourceState,
};

const [showDatasourceSwitcher, setDatasourceSwitcher] = useState(false);

return (
<>
<EuiSelect
data-test-subj="datasource-switch"
options={Object.keys(props.datasourceMap).map(datasourceId => ({
value: datasourceId,
text: datasourceId,
}))}
value={props.activeDatasource || undefined}
onChange={e => {
props.dispatch({ type: 'SWITCH_DATASOURCE', newDatasourceId: e.target.value });
}}
/>
{Object.keys(props.datasourceMap).length > 1 && (
<EuiPopover
id="datasource-switch"
className="lnsDatasourceSwitch"
button={
<EuiButtonIcon
aria-label="Switch to datasource"
title="Switch to datasource"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i18n please

data-test-subj="datasource-switch"
onClick={() => setDatasourceSwitcher(true)}
iconType="gear"
/>
}
isOpen={showDatasourceSwitcher}
closePopover={() => setDatasourceSwitcher(false)}
panelPaddingSize="none"
anchorPosition="rightUp"
>
<EuiContextMenuPanel
title="Switch to datasource"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i18n please

items={Object.keys(props.datasourceMap).map(datasourceId => (
<EuiContextMenuItem
key={datasourceId}
data-test-subj={`datasource-switch-${datasourceId}`}
icon={props.activeDatasource === datasourceId ? 'check' : 'empty'}
onClick={() => {
setDatasourceSwitcher(false);
props.dispatch({
type: 'SWITCH_DATASOURCE',
newDatasourceId: datasourceId,
});
}}
>
{datasourceId}
</EuiContextMenuItem>
))}
/>
</EuiPopover>
)}
{props.activeDatasource && !props.datasourceIsLoading && (
<NativeRenderer
className="lnsSidebarContainer"
render={props.datasourceMap[props.activeDatasource].renderDataPanel}
nativeProps={datasourceProps}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,16 @@ Object {

await waitForPromises();

const updatedState = {};
const updatedState = {
title: 'shazm',
};
const setDatasourceState = (mockDatasource.renderDataPanel as jest.Mock).mock.calls[0][1]
.setState;
act(() => {
setDatasourceState(updatedState);
});

expect(mockDatasource.renderDataPanel).toHaveBeenCalledTimes(3);
expect(mockDatasource.renderDataPanel).toHaveBeenCalledTimes(2);
expect(mockDatasource.renderDataPanel).toHaveBeenLastCalledWith(
expect.any(Element),
expect.objectContaining({
Expand Down Expand Up @@ -502,6 +504,10 @@ Object {
instance.update();
});

afterEach(() => {
instance.unmount();
});

it('should have initialized only the initial datasource and visualization', () => {
expect(mockDatasource.initialize).toHaveBeenCalled();
expect(mockDatasource2.initialize).not.toHaveBeenCalled();
Expand All @@ -512,9 +518,12 @@ Object {

it('should initialize other datasource on switch', async () => {
act(() => {
instance
.find('select[data-test-subj="datasource-switch"]')
.simulate('change', { target: { value: 'testDatasource2' } });
instance.find('button[data-test-subj="datasource-switch"]').simulate('click');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't need to wrap .simulate in act()

});
act(() => {
(document.querySelector(
'[data-test-subj="datasource-switch-testDatasource2"]'
) as HTMLButtonElement).click();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you're switching to document.querySelector vs instance.find(...).simulate('click')? This seems inconsistent

});
expect(mockDatasource2.initialize).toHaveBeenCalled();
});
Expand All @@ -523,9 +532,11 @@ Object {
const initialState = {};
mockDatasource2.initialize.mockResolvedValue(initialState);

instance
.find('select[data-test-subj="datasource-switch"]')
.simulate('change', { target: { value: 'testDatasource2' } });
instance.find('button[data-test-subj="datasource-switch"]').simulate('click');

(document.querySelector(
'[data-test-subj="datasource-switch-testDatasource2"]'
) as HTMLButtonElement).click();

await waitForPromises();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,35 @@

.lnsPageMainContent {
display: flex;
overflow: auto;
}

.lnsSidebar {
@include euiScrollBar;
overflow: hidden auto;
padding: $euiSize;
margin: 0;
flex: 1 0 18%;
min-width: ($euiSize * 16);
min-width: ($euiSize * 22);
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}

.lnsSidebar--right {
min-width: ($euiSize * 18);
min-width: ($euiSize * 22);
@include euiScrollBar;
overflow: hidden auto;
padding: $euiSize;
}

.lnsSidebarContainer {
flex: 1 0 100%;
overflow: hidden;
}

.lnsDatasourceSwitch {
position: absolute;
right: $euiSize + $euiSizeXS;
top: $euiSize + $euiSizeXS;
}

.lnsPageBody {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import React, { useState, useEffect } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';

import { EuiIcon, EuiTitle, EuiPanel, EuiIconTip } from '@elastic/eui';
import { toExpression } from '@kbn/interpreter/common';
import { i18n } from '@kbn/i18n';
Expand All @@ -15,6 +14,7 @@ import { Datasource, Visualization } from '../../types';
import { getSuggestions, toSwitchAction, Suggestion } from './suggestion_helpers';
import { ExpressionRenderer } from '../../../../../../../src/legacy/core_plugins/data/public';
import { prependDatasourceExpression } from './expression_helpers';
import { debouncedComponent } from '../../debounced_component';

export interface SuggestionPanelProps {
activeDatasource: Datasource;
Expand Down Expand Up @@ -87,7 +87,9 @@ const SuggestionPreview = ({
);
};

export function SuggestionPanel({
export const SuggestionPanel = debouncedComponent(InnerSuggestionPanel, 2000);

function InnerSuggestionPanel({
activeDatasource,
datasourceState,
activeVisualizationId,
Expand Down
Loading