Skip to content

Commit

Permalink
[Lens] Allow only current visualization on field drop in workspace (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Aug 5, 2019
1 parent 9941757 commit ce1f652
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,11 @@ describe('editor_frame', () => {
...mockDatasource,
getDatasourceSuggestionsForField: () => [generateSuggestion()],
getDatasourceSuggestionsFromCurrentState: () => [generateSuggestion()],
renderDataPanel: (_element, { dragDropContext: { setDragging, dragging } }) => {
if (dragging !== 'draggedField') {
setDragging('draggedField');
}
},
},
}}
initialDatasourceId="testDatasource"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React from 'react';

import { ExpressionRendererProps } from '../../../../../../../src/legacy/core_plugins/data/public';
import { Visualization } from '../../types';
import { Visualization, FramePublicAPI } from '../../types';
import {
createMockVisualization,
createMockDatasource,
Expand All @@ -18,13 +18,14 @@ import {
import { InnerWorkspacePanel, WorkspacePanelProps } from './workspace_panel';
import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
import { ReactWrapper } from 'enzyme';
import { DragDrop } from '../../drag_drop';
import { DragDrop, ChildDragDropProvider } from '../../drag_drop';
import { Ast } from '@kbn/interpreter/common';

const waitForPromises = () => new Promise(resolve => setTimeout(resolve));

describe('workspace_panel', () => {
let mockVisualization: jest.Mocked<Visualization>;
let mockVisualization2: jest.Mocked<Visualization>;
let mockDatasource: DatasourceMock;

let expressionRendererMock: jest.Mock<React.ReactElement, [ExpressionRendererProps]>;
Expand All @@ -33,6 +34,7 @@ describe('workspace_panel', () => {

beforeEach(() => {
mockVisualization = createMockVisualization();
mockVisualization2 = createMockVisualization();

mockDatasource = createMockDatasource();

Expand Down Expand Up @@ -452,32 +454,42 @@ describe('workspace_panel', () => {

describe('suggestions from dropping in workspace panel', () => {
let mockDispatch: jest.Mock;
let frame: jest.Mocked<FramePublicAPI>;

const draggedField: unknown = {};

beforeEach(() => {
frame = createMockFramePublicAPI();
mockDispatch = jest.fn();
});

function initComponent(draggingContext: unknown = draggedField) {
instance = mount(
<InnerWorkspacePanel
activeDatasourceId={'mock'}
datasourceStates={{
mock: {
state: {},
isLoading: false,
},
}}
datasourceMap={{
mock: mockDatasource,
}}
framePublicAPI={createMockFramePublicAPI()}
activeVisualizationId={null}
visualizationMap={{
vis: mockVisualization,
}}
visualizationState={{}}
dispatch={mockDispatch}
ExpressionRenderer={expressionRendererMock}
/>
<ChildDragDropProvider dragging={draggingContext} setDragging={() => {}}>
<InnerWorkspacePanel
activeDatasourceId={'mock'}
datasourceStates={{
mock: {
state: {},
isLoading: false,
},
}}
datasourceMap={{
mock: mockDatasource,
}}
framePublicAPI={frame}
activeVisualizationId={'vis'}
visualizationMap={{
vis: mockVisualization,
vis2: mockVisualization2,
}}
visualizationState={{}}
dispatch={mockDispatch}
ExpressionRenderer={expressionRendererMock}
/>
</ChildDragDropProvider>
);
});
}

it('should immediately transition if exactly one suggestion is returned', () => {
const expectedTable = {
Expand All @@ -501,13 +513,9 @@ describe('workspace_panel', () => {
previewIcon: 'empty',
},
]);
initComponent();

instance.find(DragDrop).prop('onDrop')!({
name: '@timestamp',
type: 'date',
searchable: false,
aggregatable: false,
});
instance.find(DragDrop).prop('onDrop')!(draggedField);

expect(mockDatasource.getDatasourceSuggestionsForField).toHaveBeenCalledTimes(1);
expect(mockVisualization.getSuggestions).toHaveBeenCalledWith(
Expand All @@ -523,6 +531,90 @@ describe('workspace_panel', () => {
});
});

it('should allow to drop if there are suggestions', () => {
mockDatasource.getDatasourceSuggestionsForField.mockReturnValueOnce([
{
state: {},
table: {
datasourceSuggestionId: 0,
isMultiRow: true,
layerId: '1',
columns: [],
},
},
]);
mockVisualization.getSuggestions.mockReturnValueOnce([
{
score: 0.5,
title: 'my title',
state: {},
datasourceSuggestionId: 0,
previewIcon: 'empty',
},
]);
initComponent();
expect(instance.find(DragDrop).prop('droppable')).toBeTruthy();
});

it('should refuse to drop if there only suggestions from other visualizations if there are data tables', () => {
frame.datasourceLayers.a = mockDatasource.publicAPIMock;
mockDatasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'a' }]);
mockDatasource.getDatasourceSuggestionsForField.mockReturnValueOnce([
{
state: {},
table: {
datasourceSuggestionId: 0,
isMultiRow: true,
layerId: '1',
columns: [],
},
},
]);
mockVisualization2.getSuggestions.mockReturnValueOnce([
{
score: 0.5,
title: 'my title',
state: {},
datasourceSuggestionId: 0,
previewIcon: 'empty',
},
]);
initComponent();
expect(instance.find(DragDrop).prop('droppable')).toBeFalsy();
});

it('should allow to drop if there are suggestions from active visualization even if there are data tables', () => {
frame.datasourceLayers.a = mockDatasource.publicAPIMock;
mockDatasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'a' }]);
mockDatasource.getDatasourceSuggestionsForField.mockReturnValueOnce([
{
state: {},
table: {
datasourceSuggestionId: 0,
isMultiRow: true,
layerId: '1',
columns: [],
},
},
]);
mockVisualization.getSuggestions.mockReturnValueOnce([
{
score: 0.5,
title: 'my title',
state: {},
datasourceSuggestionId: 0,
previewIcon: 'empty',
},
]);
initComponent();
expect(instance.find(DragDrop).prop('droppable')).toBeTruthy();
});

it('should refuse to drop if there are no suggestions', () => {
initComponent();
expect(instance.find(DragDrop).prop('droppable')).toBeFalsy();
});

it('should immediately transition to the first suggestion if there are multiple', () => {
mockDatasource.getDatasourceSuggestionsForField.mockReturnValueOnce([
{
Expand Down Expand Up @@ -563,12 +655,8 @@ describe('workspace_panel', () => {
},
]);

instance.find(DragDrop).prop('onDrop')!({
name: '@timestamp',
type: 'date',
searchable: false,
aggregatable: false,
});
initComponent();
instance.find(DragDrop).prop('onDrop')!(draggedField);

expect(mockDispatch).toHaveBeenCalledWith({
type: 'SWITCH_VISUALIZATION',
Expand All @@ -579,18 +667,5 @@ describe('workspace_panel', () => {
datasourceState: {},
});
});

it("should do nothing when the visualization can't use the suggestions", () => {
instance.find(DragDrop).prop('onDrop')!({
name: '@timestamp',
type: 'date',
searchable: false,
aggregatable: false,
});

expect(mockDatasource.getDatasourceSuggestionsForField).toHaveBeenCalledTimes(1);
expect(mockVisualization.getSuggestions).toHaveBeenCalledTimes(1);
expect(mockDispatch).not.toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,30 +49,38 @@ export function InnerWorkspacePanel({
ExpressionRenderer: ExpressionRendererComponent,
}: WorkspacePanelProps) {
const dragDropContext = useContext(DragContext);
function onDrop(item: unknown) {
if (!activeDatasourceId) {

const suggestionForDraggedField = useMemo(() => {
if (!dragDropContext.dragging || !activeDatasourceId) {
return;
}
const datasourceSuggestions = datasourceMap[
activeDatasourceId
].getDatasourceSuggestionsForField(datasourceStates[activeDatasourceId].state, item);
].getDatasourceSuggestionsForField(
datasourceStates[activeDatasourceId].state,
dragDropContext.dragging
);

const hasData = Object.values(framePublicAPI.datasourceLayers).some(
datasource => datasource.getTableSpec().length > 0
);

const suggestions = getSuggestions(
datasourceSuggestions,
visualizationMap,
hasData && activeVisualizationId
? { [activeVisualizationId]: visualizationMap[activeVisualizationId] }
: visualizationMap,
activeVisualizationId,
visualizationState
);

if (suggestions.length === 0) {
// TODO specify and implement behavior in case of no valid suggestions
return;
}
return suggestions[0];
}, [dragDropContext.dragging]);

const suggestion = suggestions[0];

// TODO heuristically present the suggestions in a modal instead of just picking the first one
dispatch(toSwitchAction(suggestion));
function onDrop() {
if (suggestionForDraggedField) {
dispatch(toSwitchAction(suggestionForDraggedField));
}
}

function renderEmptyWorkspace() {
Expand Down Expand Up @@ -151,7 +159,7 @@ export function InnerWorkspacePanel({
}

return (
<DragDrop draggable={false} droppable={Boolean(dragDropContext.dragging)} onDrop={onDrop}>
<DragDrop draggable={false} droppable={Boolean(suggestionForDraggedField)} onDrop={onDrop}>
{renderVisualization()}
</DragDrop>
);
Expand Down

0 comments on commit ce1f652

Please sign in to comment.