[Lens] Allows users to not render suggestions (#115946)

* [Lens] Allows users to not render suggestions

* Improve the transitions

* change implementation and use EuiAccordion instead

* Fixes the scrolling problem on the suggestions panel

* Apply PR comments

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Stratoula Kalafateli 2021-11-02 13:05:46 +02:00 committed by GitHub
parent 14c0d35a62
commit 29e807f2e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 61 deletions

View file

@ -1,10 +1,6 @@
@import '../../mixins';
@import '../../variables';
.lnsSuggestionPanel__title {
margin-left: $euiSizeXS / 2;
}
.lnsSuggestionPanel__suggestions {
@include euiScrollBar;
@include lnsOverflowShadowHorizontal;
@ -16,7 +12,10 @@
// Padding / negative margins to make room for overflow shadow
padding-left: $euiSizeXS;
margin-left: -$euiSizeXS;
padding-bottom: $euiSizeXS;
}
.lnsSuggestionPanel {
padding-bottom: $euiSizeS;
}
.lnsSuggestionPanel__button {

View file

@ -18,7 +18,7 @@ import { act } from 'react-dom/test-utils';
import { ReactExpressionRendererType } from '../../../../../../src/plugins/expressions/public';
import { SuggestionPanel, SuggestionPanelProps, SuggestionPanelWrapper } from './suggestion_panel';
import { getSuggestions, Suggestion } from './suggestion_helpers';
import { EuiIcon, EuiPanel, EuiToolTip } from '@elastic/eui';
import { EuiIcon, EuiPanel, EuiToolTip, EuiAccordion } from '@elastic/eui';
import { LensIconChartDatatable } from '../../assets/chart_datatable';
import { mountWithProvider } from '../../mocks';
import { LensAppState, PreviewState, setState, setToggleFullscreen } from '../../state_management';
@ -264,8 +264,10 @@ describe('suggestion_panel', () => {
preloadedState,
});
expect(instance.find(EuiIcon)).toHaveLength(1);
expect(instance.find(EuiIcon).prop('type')).toEqual(LensIconChartDatatable);
expect(instance.find('[data-test-subj="lnsSuggestionsPanel"]').find(EuiIcon)).toHaveLength(1);
expect(
instance.find('[data-test-subj="lnsSuggestionsPanel"]').find(EuiIcon).prop('type')
).toEqual(LensIconChartDatatable);
});
it('should return no suggestion if visualization has missing index-patterns', async () => {
@ -292,6 +294,16 @@ describe('suggestion_panel', () => {
expect(instance.html()).toEqual(null);
});
it('should hide the selections when the accordion is hidden', async () => {
const { instance } = await mountWithProvider(<SuggestionPanel {...defaultProps} />);
expect(instance.find(EuiAccordion)).toHaveLength(1);
act(() => {
instance.find(EuiAccordion).at(0).simulate('change');
});
expect(instance.find('[data-test-subj="lnsSuggestionsPanel"]')).toEqual({});
});
it('should render preview expression if there is one', () => {
mockDatasource.getLayers.mockReturnValue(['first']);
(getSuggestions as jest.Mock).mockReturnValue([

View file

@ -8,17 +8,17 @@
import './suggestion_panel.scss';
import { camelCase, pick } from 'lodash';
import React, { useState, useEffect, useMemo, useRef } from 'react';
import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import useLocalStorage from 'react-use/lib/useLocalStorage';
import {
EuiIcon,
EuiTitle,
EuiPanel,
EuiIconTip,
EuiToolTip,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiAccordion,
} from '@elastic/eui';
import { IconType } from '@elastic/eui/src/components/icon/icon';
import { Ast, toExpression } from '@kbn/interpreter/common';
@ -58,6 +58,7 @@ import {
} from '../../state_management';
const MAX_SUGGESTIONS_DISPLAYED = 5;
const LOCAL_STORAGE_SUGGESTIONS_PANEL = 'LENS_SUGGESTIONS_PANEL_HIDDEN';
export interface SuggestionPanelProps {
datasourceMap: DatasourceMap;
@ -189,6 +190,15 @@ export function SuggestionPanel({
const existsStagedPreview = useLensSelector((state) => Boolean(state.lens.stagedPreview));
const currentVisualization = useLensSelector(selectCurrentVisualization);
const currentDatasourceStates = useLensSelector(selectCurrentDatasourceStates);
// get user's selection from localStorage, this key defines if the suggestions panel will be hidden or not
const [hideSuggestions, setHideSuggestions] = useLocalStorage(
LOCAL_STORAGE_SUGGESTIONS_PANEL,
false
);
const toggleSuggestions = useCallback(() => {
setHideSuggestions(!hideSuggestions);
}, [setHideSuggestions, hideSuggestions]);
const missingIndexPatterns = getMissingIndexPattern(
activeDatasourceId ? datasourceMap[activeDatasourceId] : null,
@ -322,9 +332,10 @@ export function SuggestionPanel({
return (
<div className="lnsSuggestionPanel">
<EuiFlexGroup alignItems="center">
<EuiFlexItem>
<EuiTitle className="lnsSuggestionPanel__title" size="xxs">
<EuiAccordion
id="lensSuggestionsPanel"
buttonContent={
<EuiTitle size="xxs">
<h3>
<FormattedMessage
id="xpack.lens.editorFrame.suggestionPanelTitle"
@ -332,9 +343,12 @@ export function SuggestionPanel({
/>
</h3>
</EuiTitle>
</EuiFlexItem>
{existsStagedPreview && (
<EuiFlexItem grow={false}>
}
forceState={hideSuggestions ? 'closed' : 'open'}
onToggle={toggleSuggestions}
extraAction={
existsStagedPreview &&
!hideSuggestions && (
<EuiToolTip
content={i18n.translate('xpack.lens.suggestion.refreshSuggestionTooltip', {
defaultMessage: 'Refresh the suggestions based on the selected visualization.',
@ -354,54 +368,55 @@ export function SuggestionPanel({
})}
</EuiButtonEmpty>
</EuiToolTip>
</EuiFlexItem>
)}
</EuiFlexGroup>
<div className="lnsSuggestionPanel__suggestions">
{currentVisualization.activeId && (
<SuggestionPreview
preview={{
error: currentStateError != null,
expression: currentStateExpression,
icon:
visualizationMap[currentVisualization.activeId].getDescription(
currentVisualization.state
).icon || 'empty',
title: i18n.translate('xpack.lens.suggestions.currentVisLabel', {
defaultMessage: 'Current visualization',
}),
}}
ExpressionRenderer={AutoRefreshExpressionRenderer}
onSelect={rollbackToCurrentVisualization}
selected={lastSelectedSuggestion === -1}
showTitleAsLabel
/>
)}
{suggestions.map((suggestion, index) => {
return (
)
}
>
<div className="lnsSuggestionPanel__suggestions" data-test-subj="lnsSuggestionsPanel">
{currentVisualization.activeId && !hideSuggestions && (
<SuggestionPreview
preview={{
expression: suggestion.previewExpression,
icon: suggestion.previewIcon,
title: suggestion.title,
error: currentStateError != null,
expression: currentStateExpression,
icon:
visualizationMap[currentVisualization.activeId].getDescription(
currentVisualization.state
).icon || 'empty',
title: i18n.translate('xpack.lens.suggestions.currentVisLabel', {
defaultMessage: 'Current visualization',
}),
}}
ExpressionRenderer={AutoRefreshExpressionRenderer}
key={index}
onSelect={() => {
trackUiEvent('suggestion_clicked');
if (lastSelectedSuggestion === index) {
rollbackToCurrentVisualization();
} else {
setLastSelectedSuggestion(index);
switchToSuggestion(dispatchLens, suggestion);
}
}}
selected={index === lastSelectedSuggestion}
onSelect={rollbackToCurrentVisualization}
selected={lastSelectedSuggestion === -1}
showTitleAsLabel
/>
);
})}
</div>
)}
{!hideSuggestions &&
suggestions.map((suggestion, index) => {
return (
<SuggestionPreview
preview={{
expression: suggestion.previewExpression,
icon: suggestion.previewIcon,
title: suggestion.title,
}}
ExpressionRenderer={AutoRefreshExpressionRenderer}
key={index}
onSelect={() => {
trackUiEvent('suggestion_clicked');
if (lastSelectedSuggestion === index) {
rollbackToCurrentVisualization();
} else {
setLastSelectedSuggestion(index);
switchToSuggestion(dispatchLens, suggestion);
}
}}
selected={index === lastSelectedSuggestion}
/>
);
})}
</div>
</EuiAccordion>
</div>
);
}

View file

@ -1,6 +1,6 @@
.lnsVisualizationContainer {
@include euiScrollBar;
overflow: auto;
overflow: auto hidden;
user-select: text;
}