Commit 7c74bda4 authored by Eulyeon Ko's avatar Eulyeon Ko Committed by Heinrich Lee Yu

Add draggable item type as data attribute

Items that are draggable are given a new data attribute
"draggable-item-type".

The handlers for draggable should check the attribute
of an item before handling an event.
parent 3f6610db
......@@ -6,10 +6,12 @@ import { mapState, mapGetters, mapActions } from 'vuex';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
import defaultSortableConfig from '~/sortable/sortable_config';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DraggableItemTypes } from '../constants';
import BoardColumn from './board_column.vue';
import BoardColumnDeprecated from './board_column_deprecated.vue';
export default {
draggableItemTypes: DraggableItemTypes,
components: {
BoardAddNewColumn,
BoardColumn,
......@@ -99,6 +101,7 @@ export default {
:key="index"
ref="board"
:list="list"
:data-draggable-item-type="$options.draggableItemTypes.list"
:disabled="disabled"
/>
......
......@@ -6,12 +6,13 @@ import { sortableStart, sortableEnd } from '~/boards/mixins/sortable_default_opt
import { sprintf, __ } from '~/locale';
import defaultSortableConfig from '~/sortable/sortable_config';
import Tracking from '~/tracking';
import { toggleFormEventPrefix } from '../constants';
import { toggleFormEventPrefix, DraggableItemTypes } from '../constants';
import eventHub from '../eventhub';
import BoardCard from './board_card.vue';
import BoardNewIssue from './board_new_issue.vue';
export default {
draggableItemTypes: DraggableItemTypes,
name: 'BoardList',
i18n: {
loading: __('Loading'),
......@@ -170,15 +171,33 @@ export default {
this.loadNextPage();
}
},
handleDragOnStart() {
handleDragOnStart({
item: {
dataset: { draggableItemType },
},
}) {
if (draggableItemType !== DraggableItemTypes.card) {
return;
}
sortableStart();
this.track('drag_card', { label: 'board' });
},
handleDragOnEnd(params) {
handleDragOnEnd({
newIndex: originalNewIndex,
oldIndex,
from,
to,
item: {
dataset: { draggableItemType, itemId, itemIid, itemPath },
},
}) {
if (draggableItemType !== DraggableItemTypes.card) {
return;
}
sortableEnd();
const { oldIndex, from, to, item } = params;
let { newIndex } = params;
const { itemId, itemIid, itemPath } = item.dataset;
let newIndex = originalNewIndex;
let { children } = to;
let moveBeforeId;
let moveAfterId;
......@@ -265,6 +284,7 @@ export default {
:index="index"
:list="list"
:item="item"
:data-draggable-item-type="$options.draggableItemTypes.card"
:disabled="disabled"
/>
<gl-intersection-observer @appear="onReachingListBottom">
......
......@@ -113,6 +113,11 @@ export const FilterFields = {
],
};
export const DraggableItemTypes = {
card: 'card',
list: 'list',
};
export default {
BoardType,
ListType,
......
......@@ -14,6 +14,7 @@ import {
issuableTypes,
FilterFields,
ListTypeTitles,
DraggableItemTypes,
} from 'ee_else_ce/boards/constants';
import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create.mutation.graphql';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
......@@ -267,12 +268,16 @@ export default {
{ state: { boardLists }, commit, dispatch },
{
item: {
dataset: { listId: movedListId },
dataset: { listId: movedListId, draggableItemType },
},
newIndex,
to: { children },
},
) => {
if (draggableItemType !== DraggableItemTypes.list) {
return;
}
const displacedListId = children[newIndex].dataset.listId;
if (movedListId === displacedListId) {
return;
......
import Draggable from 'vuedraggable';
import { DraggableItemTypes } from 'ee_else_ce/boards/constants';
import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
import createComponent from 'jest/boards/board_list_helper';
import BoardCard from '~/boards/components/board_card.vue';
......@@ -13,6 +14,22 @@ describe('Board list component', () => {
const findIssueCountLoadingIcon = () => wrapper.find('[data-testid="count-loading-icon"]');
const findDraggable = () => wrapper.findComponent(Draggable);
const startDrag = (
params = {
item: {
dataset: {
draggableItemType: DraggableItemTypes.card,
},
},
},
) => {
findByTestId('tree-root-wrapper').vm.$emit('start', params);
};
const endDrag = (params) => {
findByTestId('tree-root-wrapper').vm.$emit('end', params);
};
useFakeRequestAnimationFrame();
afterEach(() => {
......@@ -174,22 +191,28 @@ describe('Board list component', () => {
it('adds a class `is-dragging` to document body', () => {
expect(document.body.classList.contains('is-dragging')).toBe(false);
findByTestId('tree-root-wrapper').vm.$emit('start');
startDrag();
expect(document.body.classList.contains('is-dragging')).toBe(true);
});
});
describe('handleDragOnEnd', () => {
it('removes class `is-dragging` from document body', () => {
beforeEach(() => {
jest.spyOn(wrapper.vm, 'moveItem').mockImplementation(() => {});
startDrag();
});
it('removes class `is-dragging` from document body', () => {
document.body.classList.add('is-dragging');
findByTestId('tree-root-wrapper').vm.$emit('end', {
endDrag({
oldIndex: 1,
newIndex: 0,
item: {
dataset: {
draggableItemType: DraggableItemTypes.card,
itemId: mockIssues[0].id,
itemIid: mockIssues[0].iid,
itemPath: mockIssues[0].referencePath,
......@@ -201,6 +224,25 @@ describe('Board list component', () => {
expect(document.body.classList.contains('is-dragging')).toBe(false);
});
it(`should not handle the event if the dragged item is not a "${DraggableItemTypes.card}"`, () => {
endDrag({
oldIndex: 1,
newIndex: 0,
item: {
dataset: {
draggableItemType: DraggableItemTypes.list,
itemId: mockIssues[0].id,
itemIid: mockIssues[0].iid,
itemPath: mockIssues[0].referencePath,
},
},
to: { children: [], dataset: { listId: 'gid://gitlab/List/1' } },
from: { dataset: { listId: 'gid://gitlab/List/2' } },
});
expect(document.body.classList.contains('is-dragging')).toBe(true);
});
});
});
......
......@@ -9,6 +9,7 @@ import {
issuableTypes,
BoardType,
listsQuery,
DraggableItemTypes,
} from 'ee_else_ce/boards/constants';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
import testAction from 'helpers/vuex_action_helper';
......@@ -525,6 +526,21 @@ describe('moveList', () => {
const movableListsOrder = ['gid://3', 'gid://4', 'gid://5'];
const allListsOrder = [backlogListId, ...movableListsOrder, closedListId];
it(`should not handle the event if the dragged item is not a "${DraggableItemTypes.list}"`, () => {
return testAction({
action: actions.moveList,
payload: {
item: { dataset: { listId: '', draggableItemType: DraggableItemTypes.card } },
to: {
children: [],
},
},
state: {},
expectedMutations: [],
expectedActions: [],
});
});
describe.each`
draggableFrom | draggableTo | boardLists | boardListsOrder | expectedMovableListsOrder
${0} | ${2} | ${boardLists1} | ${movableListsOrder} | ${['gid://4', 'gid://5', 'gid://3']}
......@@ -544,7 +560,12 @@ describe('moveList', () => {
const displacedListId = boardListsOrder[draggableTo];
const buildDraggablePayload = () => {
return {
item: { dataset: { listId: boardListsOrder[draggableFrom] } },
item: {
dataset: {
listId: boardListsOrder[draggableFrom],
draggableItemType: DraggableItemTypes.list,
},
},
newIndex: draggableTo,
to: {
children: boardListsOrder.map((listId) => ({ dataset: { listId } })),
......@@ -584,7 +605,7 @@ describe('moveList', () => {
return testAction({
action: actions.moveList,
payload: {
item: { dataset: { listId } },
item: { dataset: { listId, draggbaleItemType: DraggableItemTypes.list } },
newIndex: 0,
to: {
children: [{ dataset: { listId } }],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment