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