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] Drag within dimension group to reorder #80547

Merged
merged 51 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ebbf9c9
feat: dnd to reorder
mbondyra Oct 10, 2020
a1e0827
tests for droppable
mbondyra Oct 19, 2020
e7c0070
test for layer_panel
mbondyra Oct 19, 2020
029e3c8
tests
mbondyra Oct 19, 2020
3d6671b
fixes
mbondyra Oct 19, 2020
d19edb2
Update drag_drop.tsx
mbondyra Oct 19, 2020
35a2ee6
Caroline's CR
mbondyra Oct 20, 2020
135f9f6
Merge branch 'lens/dnd_to_reorder' of github.com:mbondyra/kibana into…
mbondyra Oct 20, 2020
c9ae3b1
fix typo
mbondyra Oct 20, 2020
ec17a13
eslint
mbondyra Oct 20, 2020
9f06afa
cr
mbondyra Oct 21, 2020
8ceb7d5
keyboard interactivity
mbondyra Oct 21, 2020
915c8c6
move to reorder with EuiScreenReaderOnly
mbondyra Oct 21, 2020
60ad975
keyboard and accessibility
mbondyra Oct 21, 2020
da7f9e2
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Oct 21, 2020
fba67ea
fix: types
mbondyra Oct 21, 2020
9636d84
Merge branch 'lens/dnd_to_reorder' of github.com:mbondyra/kibana into…
mbondyra Oct 21, 2020
f39fe13
var name change
mbondyra Oct 21, 2020
c3d0984
tests
mbondyra Oct 21, 2020
b723e1a
Merge remote-tracking branch 'origin/master' into HEAD
wylieconlon Oct 22, 2020
05b67fa
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Oct 26, 2020
9e2585b
Wylie's CR
mbondyra Oct 26, 2020
2c3c238
refactor tests
mbondyra Oct 26, 2020
69500ae
tests
mbondyra Oct 26, 2020
1c9366f
refactor reorder to inside
mbondyra Oct 26, 2020
2c38462
still no fix
mbondyra Oct 26, 2020
b0ebbf7
one fix for field dnd items
mbondyra Oct 27, 2020
bb381b0
accessibility work
mbondyra Oct 27, 2020
1ea6aa9
accessibility changes
mbondyra Oct 27, 2020
4fb3985
types
mbondyra Oct 27, 2020
c4a26a2
more accessibility improvements
mbondyra Oct 27, 2020
9752f60
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Oct 28, 2020
b05c3f2
fix: different components height
mbondyra Oct 28, 2020
8c4572c
Merge branch 'lens/dnd_to_reorder' of github.com:mbondyra/kibana into…
mbondyra Oct 28, 2020
a94bcb9
fix weird twitching
flash1293 Oct 28, 2020
e4e3ef9
Merge branch 'lens/dnd_to_reorder' of github.com:mbondyra/kibana into…
flash1293 Oct 28, 2020
4b20fad
make sure drop targets are not hovered
flash1293 Oct 28, 2020
69fe238
Merge branch 'lens/dnd_to_reorder' of github.com:mbondyra/kibana into…
mbondyra Oct 28, 2020
b1341f4
revert unnecessary changes
mbondyra Oct 29, 2020
9274c2f
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Oct 29, 2020
d513053
moving with accessibility announcement to portal
mbondyra Oct 29, 2020
8549bf7
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Oct 29, 2020
9be0338
removing dead code
mbondyra Oct 30, 2020
cac17f1
doc description
mbondyra Oct 30, 2020
f754fd4
CR corrections
mbondyra Nov 2, 2020
c35d414
design changes
mbondyra Nov 2, 2020
878384e
eslint
mbondyra Nov 2, 2020
c9c6651
Merge branch 'master' into lens/dnd_to_reorder
kibanamachine Nov 2, 2020
14625f1
no message
mbondyra Nov 2, 2020
f2f19e4
visual changes in the code
mbondyra Nov 3, 2020
5e220b8
Merge commit 'c974f56e1ca9ddd0c5f0460fd2737ae8c580716f' into lens/dnd…
mbondyra Nov 3, 2020
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
1 change: 1 addition & 0 deletions x-pack/plugins/lens/public/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ $lnsPanelMinWidth: $euiSize * 18;
// These sizes also match canvas' page thumbnails for consistency
$lnsSuggestionHeight: 100px;
$lnsSuggestionWidth: 150px;
$lnsLayerPanelDimensionMargin: 8px;
44 changes: 39 additions & 5 deletions x-pack/plugins/lens/public/drag_drop/drag_drop.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@
}
}

// Draggable item when it is moving
.lnsDragDrop-isHidden {
opacity: 0;
}

// Drop area
.lnsDragDrop-isDroppable {
@include lnsDroppable;
Expand All @@ -35,6 +30,10 @@
@include lnsDroppableActive;
}

.lnsDragDrop-isActiveGroup {
background-color: transparentize($euiColorVis0, .8);
mbondyra marked this conversation as resolved.
Show resolved Hide resolved
}

// Drop area while hovering with item
.lnsDragDrop-isActiveDropTarget {
@include lnsDroppableActiveHover;
Expand All @@ -52,3 +51,38 @@
text-decoration: line-through;
}
}

.lnsDragDrop__reorderableContainer {
position: relative;
}

.lnsDragDrop__reorderableDrop {
position: absolute;
width: 100%;
top: 0;
height: calc(100% + #{$lnsLayerPanelDimensionMargin});
}

.lnsDragDrop-isReorderable {
transition: transform $euiAnimSpeedFast ease-in-out;
pointer-events: none;
}

// Draggable item when it is moving
.lnsDragDrop-isHidden {
opacity: 0;
}

.lnsDragDrop__keyboardHandler {
top: 0;
position: absolute;
width: 100%;
height: 100%;
border-radius: $euiBorderRadius;

&:focus,
&:focus-within {
@include euiFocusRing;
pointer-events: none;
}
}
194 changes: 180 additions & 14 deletions x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@

import React from 'react';
import { render, mount } from 'enzyme';
import { DragDrop } from './drag_drop';
import { ChildDragDropProvider } from './providers';
import { DragDrop, ReorderableDragDrop, DropToHandler, DropHandler } from './drag_drop';
import { ChildDragDropProvider, ReorderProvider } from './providers';

jest.useFakeTimers();

describe('DragDrop', () => {
const value = { id: '1', label: 'hello' };
test('renders if nothing is being dragged', () => {
const component = render(
<DragDrop value="hello" draggable label="dragging">
<DragDrop value={value} draggable label="dragging">
<button>Hello!</button>
</DragDrop>
);
Expand Down Expand Up @@ -54,7 +55,6 @@ describe('DragDrop', () => {
setData: jest.fn(),
getData: jest.fn(),
};
const value = {};

const component = mount(
<ChildDragDropProvider dragging={value} setDragging={setDragging}>
Expand All @@ -77,10 +77,9 @@ describe('DragDrop', () => {
const stopPropagation = jest.fn();
const setDragging = jest.fn();
const onDrop = jest.fn();
const value = {};

const component = mount(
<ChildDragDropProvider dragging="hola" setDragging={setDragging}>
<ChildDragDropProvider dragging={{ id: '2', label: 'hi' }} setDragging={setDragging}>
<DragDrop onDrop={onDrop} droppable={true} value={value}>
<button>Hello!</button>
</DragDrop>
Expand All @@ -94,7 +93,7 @@ describe('DragDrop', () => {
expect(preventDefault).toBeCalled();
expect(stopPropagation).toBeCalled();
expect(setDragging).toBeCalledWith(undefined);
expect(onDrop).toBeCalledWith('hola');
expect(onDrop).toBeCalledWith({ id: '2', label: 'hi' });
});

test('drop function is not called on droppable=false', async () => {
Expand All @@ -104,8 +103,8 @@ describe('DragDrop', () => {
const onDrop = jest.fn();

const component = mount(
<ChildDragDropProvider dragging="hola" setDragging={setDragging}>
<DragDrop onDrop={onDrop} droppable={false} value={{}}>
<ChildDragDropProvider dragging={{ id: 'hi' }} setDragging={setDragging}>
<DragDrop onDrop={onDrop} droppable={false} value={value}>
<button>Hello!</button>
</DragDrop>
</ChildDragDropProvider>
Expand Down Expand Up @@ -138,8 +137,8 @@ describe('DragDrop', () => {

test('items that have droppable=false get special styling when another item is dragged', () => {
const component = mount(
<ChildDragDropProvider dragging={'ignored'} setDragging={() => {}}>
<DragDrop value="ignored" draggable={true} label="a">
<ChildDragDropProvider dragging={value} setDragging={() => {}}>
<DragDrop value={value} draggable={true} label="a">
<button>Hello!</button>
</DragDrop>
<DragDrop onDrop={(x: unknown) => {}} droppable={false}>
Expand All @@ -152,16 +151,16 @@ describe('DragDrop', () => {
});

test('additional styles are reflected in the className until drop', () => {
let dragging: string | undefined;
let dragging: { id: '1' } | undefined;
const getAdditionalClasses = jest.fn().mockReturnValue('additional');
const component = mount(
<ChildDragDropProvider
dragging={dragging}
setDragging={() => {
dragging = 'hello';
dragging = { id: '1' };
}}
>
<DragDrop value="ignored" draggable={true} label="a">
<DragDrop value={{ label: 'ignored', id: '3' }} draggable={true} label="a">
<button>Hello!</button>
</DragDrop>
<DragDrop
Expand Down Expand Up @@ -194,4 +193,171 @@ describe('DragDrop', () => {
component.find('[data-test-subj="lnsDragDrop"]').at(1).simulate('drop');
expect(component.find('.additional')).toHaveLength(0);
});

describe('reordering', () => {
const mountComponent = (
dragging: { id: '1' } | undefined,
onDrop: DropHandler = jest.fn(),
dropTo: DropToHandler = jest.fn()
) =>
mount(
<ChildDragDropProvider
dragging={{ id: '1' }}
setDragging={() => {
dragging = { id: '1' };
}}
>
<ReorderProvider id="groupId">
<DragDrop
label="1"
draggable
droppable
dragType="reorder"
dropType="reorder"
itemsInGroup={['1', '2', '3']}
value={{ id: '1' }}
onDrop={onDrop}
dropTo={dropTo}
>
<span>1</span>
</DragDrop>
<DragDrop
label="2"
draggable
droppable
dragType="reorder"
dropType="reorder"
itemsInGroup={['1', '2', '3']}
value={{
id: '2',
}}
onDrop={onDrop}
dropTo={dropTo}
>
<span>2</span>
</DragDrop>
<DragDrop
label="3"
draggable
droppable
dragType="reorder"
dropType="reorder"
itemsInGroup={['1', '2', '3']}
value={{
id: '3',
}}
onDrop={onDrop}
dropTo={dropTo}
>
<span>3</span>
</DragDrop>
</ReorderProvider>
</ChildDragDropProvider>
);
test(`ReorderableDragDrop component doesn't appear for groups of 1 or less`, () => {
let dragging;
const component = mount(
<ChildDragDropProvider
dragging={dragging}
setDragging={() => {
dragging = { id: '1' };
}}
>
<ReorderProvider id="groupId">
<DragDrop
label="1"
draggable
droppable
dragType="reorder"
dropType="reorder"
itemsInGroup={['1']}
value={{ id: '1' }}
onDrop={jest.fn()}
dropTo={jest.fn()}
>
<div />
</DragDrop>
</ReorderProvider>
</ChildDragDropProvider>
);
expect(component.find(ReorderableDragDrop)).toHaveLength(0);
});
test(`Reorderable component renders properly`, () => {
const component = mountComponent(undefined, jest.fn());
expect(component.find(ReorderableDragDrop)).toHaveLength(3);
});
test(`Elements between dragged and drop get extra class to show the reorder effect when dragging`, () => {
const component = mountComponent({ id: '1' }, jest.fn());
const dataTransfer = {
setData: jest.fn(),
getData: jest.fn(),
};
component
.find(ReorderableDragDrop)
.first()
.find('[data-test-subj="lnsDragDrop"]')
.simulate('dragstart', { dataTransfer });
jest.runAllTimers();

component.find('[data-test-subj="lnsDragDrop-reorderableDrop"]').at(2).simulate('dragover');
expect(component.find('[data-test-subj="lnsDragDrop"]').at(0).prop('style')).toEqual({});
expect(component.find('[data-test-subj="lnsDragDrop"]').at(1).prop('style')).toEqual({
transform: 'translateY(-8px)',
});
expect(component.find('[data-test-subj="lnsDragDrop"]').at(2).prop('style')).toEqual({
transform: 'translateY(-8px)',
});

component.find('[data-test-subj="lnsDragDrop-reorderableDrop"]').at(2).simulate('dragleave');
expect(component.find('[data-test-subj="lnsDragDrop"]').at(1).prop('style')).toEqual({});
expect(component.find('[data-test-subj="lnsDragDrop"]').at(2).prop('style')).toEqual({});
});
test(`Dropping an item runs onDrop function`, () => {
const preventDefault = jest.fn();
const stopPropagation = jest.fn();
const onDrop = jest.fn();

const component = mountComponent({ id: '1' }, onDrop);

component
.find('[data-test-subj="lnsDragDrop-reorderableDrop"]')
.at(1)
.simulate('drop', { preventDefault, stopPropagation });
expect(preventDefault).toBeCalled();
expect(stopPropagation).toBeCalled();
expect(onDrop).toBeCalledWith({ id: '1' });
});
test(`Keyboard navigation: user can reorder an element`, () => {
const onDrop = jest.fn();
const dropTo = jest.fn();
const component = mountComponent({ id: '1' }, onDrop, dropTo);
const keyboardHandler = component
.find(ReorderableDragDrop)
.at(1)
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]');

keyboardHandler.simulate('keydown', { key: 'Space' });
keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
expect(dropTo).toBeCalledWith('3');

keyboardHandler.simulate('keydown', { key: 'ArrowUp' });
expect(dropTo).toBeCalledWith('1');
});
test(`Keyboard Navigation: User cannot move an element outside of the group`, () => {
const onDrop = jest.fn();
const dropTo = jest.fn();
const component = mountComponent({ id: '1' }, onDrop, dropTo);
const keyboardHandler = component
.find(ReorderableDragDrop)
.first()
.find('[data-test-subj="lnsDragDrop-keyboardHandler"]');

keyboardHandler.simulate('keydown', { key: 'Space' });
keyboardHandler.simulate('keydown', { key: 'ArrowUp' });
expect(dropTo).not.toHaveBeenCalled();

keyboardHandler.simulate('keydown', { key: 'ArrowDown' });
expect(dropTo).toBeCalledWith('2');
});
});
});
Loading