Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
b5a490db
Commit
b5a490db
authored
Sep 03, 2020
by
Florie Guibert
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Swimlanes - Drag & Drop issue between lists
VueX action and GraphQL mutation to move issue between lists
parent
8ef94193
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
459 additions
and
27 deletions
+459
-27
app/assets/javascripts/boards/boards_util.js
app/assets/javascripts/boards/boards_util.js
+32
-1
app/assets/javascripts/boards/components/board_card_layout.vue
...ssets/javascripts/boards/components/board_card_layout.vue
+2
-0
app/assets/javascripts/boards/models/issue.js
app/assets/javascripts/boards/models/issue.js
+1
-1
app/assets/javascripts/boards/queries/issue.fragment.graphql
app/assets/javascripts/boards/queries/issue.fragment.graphql
+1
-0
app/assets/javascripts/boards/queries/issue_move_list.mutation.graphql
...vascripts/boards/queries/issue_move_list.mutation.graphql
+28
-0
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+37
-2
app/assets/javascripts/boards/stores/mutation_types.js
app/assets/javascripts/boards/stores/mutation_types.js
+3
-3
app/assets/javascripts/boards/stores/mutations.js
app/assets/javascripts/boards/stores/mutations.js
+42
-6
ee/app/assets/javascripts/boards/components/epic_lane.vue
ee/app/assets/javascripts/boards/components/epic_lane.vue
+6
-0
ee/app/assets/javascripts/boards/components/epics_swimlanes.vue
.../assets/javascripts/boards/components/epics_swimlanes.vue
+2
-0
ee/app/assets/javascripts/boards/components/issues_lane_list.vue
...assets/javascripts/boards/components/issues_lane_list.vue
+72
-3
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/frontend/boards/mock_data.js
spec/frontend/boards/mock_data.js
+39
-1
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+110
-2
spec/frontend/boards/stores/mutations_spec.js
spec/frontend/boards/stores/mutations_spec.js
+81
-8
No files found.
app/assets/javascripts/boards/boards_util.js
View file @
b5a490db
import
{
sortBy
}
from
'
lodash
'
;
import
ListIssue
from
'
ee_else_ce/boards/models/issue
'
;
import
{
ListType
}
from
'
./constants
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
export
function
getMilestone
()
{
return
null
;
}
export
function
formatIssue
(
issue
)
{
return
new
ListIssue
({
...
issue
,
labels
:
issue
.
labels
?.
nodes
||
[],
assignees
:
issue
.
assignees
?.
nodes
||
[],
});
}
export
function
formatListIssues
(
listIssues
)
{
const
issues
=
{};
const
listData
=
listIssues
.
nodes
.
reduce
((
map
,
list
)
=>
{
const
sortedIssues
=
sortBy
(
list
.
issues
.
nodes
,
'
relativePosition
'
);
return
{
...
map
,
[
list
.
id
]:
list
.
issues
.
nod
es
.
map
(
i
=>
{
[
list
.
id
]:
sortedIssu
es
.
map
(
i
=>
{
const
id
=
getIdFromGraphQLId
(
i
.
id
);
const
listIssue
=
new
ListIssue
({
...
...
@@ -35,7 +46,27 @@ export function fullBoardId(boardId) {
return
`gid://gitlab/Board/
${
boardId
}
`
;
}
export
function
moveIssueListHelper
(
issue
,
fromList
,
toList
)
{
if
(
toList
.
type
===
ListType
.
label
)
{
issue
.
addLabel
(
toList
.
label
);
}
if
(
fromList
&&
fromList
.
type
===
ListType
.
label
)
{
issue
.
removeLabel
(
fromList
.
label
);
}
if
(
toList
.
type
===
ListType
.
assignee
)
{
issue
.
addAssignee
(
toList
.
assignee
);
}
if
(
fromList
&&
fromList
.
type
===
ListType
.
assignee
)
{
issue
.
removeAssignee
(
fromList
.
assignee
);
}
return
issue
;
}
export
default
{
getMilestone
,
formatIssue
,
formatListIssues
,
fullBoardId
,
};
app/assets/javascripts/boards/components/board_card_layout.vue
View file @
b5a490db
...
...
@@ -95,6 +95,8 @@ export default {
}"
:index="index"
:data-issue-id="issue.id"
:data-issue-iid="issue.iid"
:data-issue-path="issue.referencePath"
data-testid="board_card"
class="board-card p-3 rounded"
@mousedown="mouseDown"
...
...
app/assets/javascripts/boards/models/issue.js
View file @
b5a490db
...
...
@@ -15,7 +15,7 @@ class ListIssue {
this
.
labels
=
[];
this
.
assignees
=
[];
this
.
selected
=
false
;
this
.
position
=
obj
.
position
||
obj
.
relative_position
||
Infinity
;
this
.
position
=
obj
.
position
||
obj
.
relative_position
||
obj
.
relativePosition
||
Infinity
;
this
.
isFetching
=
{
subscriptions
:
true
,
};
...
...
app/assets/javascripts/boards/queries/issue.fragment.graphql
View file @
b5a490db
...
...
@@ -12,6 +12,7 @@ fragment IssueNode on Issue {
webUrl
subscribed
blocked
relativePosition
epic
{
id
}
...
...
app/assets/javascripts/boards/queries/issue_move_list.mutation.graphql
0 → 100644
View file @
b5a490db
#import "./issue.fragment.graphql"
mutation
IssueMoveList
(
$projectPath
:
ID
!
$iid
:
String
!
$boardId
:
ID
!
$fromListId
:
ID
$toListId
:
ID
$moveBeforeId
:
ID
$moveAfterId
:
ID
)
{
issueMoveList
(
input
:
{
projectPath
:
$projectPath
iid
:
$iid
boardId
:
$boardId
fromListId
:
$fromListId
toListId
:
$toListId
moveBeforeId
:
$moveBeforeId
moveAfterId
:
$moveAfterId
}
)
{
issue
{
...
IssueNode
}
errors
}
}
app/assets/javascripts/boards/stores/actions.js
View file @
b5a490db
...
...
@@ -15,6 +15,7 @@ import projectBoardQuery from '../queries/project_board.query.graphql';
import
groupBoardQuery
from
'
../queries/group_board.query.graphql
'
;
import
createBoardListMutation
from
'
../queries/board_list_create.mutation.graphql
'
;
import
updateBoardListMutation
from
'
../queries/board_list_update.mutation.graphql
'
;
import
issueMoveListMutation
from
'
../queries/issue_move_list.mutation.graphql
'
;
const
notImplemented
=
()
=>
{
/* eslint-disable-next-line @gitlab/require-i18n-strings */
...
...
@@ -227,8 +228,42 @@ export default {
.
catch
(()
=>
commit
(
types
.
RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE
));
},
moveIssue
:
()
=>
{
notImplemented
();
moveIssue
:
(
{
state
,
commit
},
{
issueId
,
issueIid
,
issuePath
,
fromListId
,
toListId
,
moveBeforeId
,
moveAfterId
},
)
=>
{
const
originalIssue
=
state
.
issues
[
issueId
];
const
fromList
=
state
.
issuesByListId
[
fromListId
];
const
originalIndex
=
fromList
.
indexOf
(
Number
(
issueId
));
commit
(
types
.
MOVE_ISSUE
,
{
originalIssue
,
fromListId
,
toListId
,
moveBeforeId
,
moveAfterId
});
const
{
boardId
}
=
state
.
endpoints
;
const
[
groupPath
,
project
]
=
issuePath
.
split
(
/
[/
#
]
/
);
gqlClient
.
mutate
({
mutation
:
issueMoveListMutation
,
variables
:
{
projectPath
:
`
${
groupPath
}
/
${
project
}
`
,
boardId
:
fullBoardId
(
boardId
),
iid
:
issueIid
,
fromListId
:
getIdFromGraphQLId
(
fromListId
),
toListId
:
getIdFromGraphQLId
(
toListId
),
moveBeforeId
,
moveAfterId
,
},
})
.
then
(({
data
})
=>
{
if
(
data
?.
issueMoveList
?.
errors
.
length
)
{
commit
(
types
.
MOVE_ISSUE_FAILURE
,
{
originalIssue
,
fromListId
,
toListId
,
originalIndex
});
}
else
{
const
issue
=
data
.
issueMoveList
?.
issue
;
commit
(
types
.
MOVE_ISSUE_SUCCESS
,
{
issue
});
}
})
.
catch
(()
=>
commit
(
types
.
MOVE_ISSUE_FAILURE
,
{
originalIssue
,
fromListId
,
toListId
,
originalIndex
}),
);
},
createNewIssue
:
()
=>
{
...
...
app/assets/javascripts/boards/stores/mutation_types.js
View file @
b5a490db
...
...
@@ -18,9 +18,9 @@ export const RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE = 'RECEIVE_ISSUES_FOR_ALL_LIST
export
const
REQUEST_ADD_ISSUE
=
'
REQUEST_ADD_ISSUE
'
;
export
const
RECEIVE_ADD_ISSUE_SUCCESS
=
'
RECEIVE_ADD_ISSUE_SUCCESS
'
;
export
const
RECEIVE_ADD_ISSUE_ERROR
=
'
RECEIVE_ADD_ISSUE_ERROR
'
;
export
const
REQUEST_MOVE_ISSUE
=
'
REQUEST_
MOVE_ISSUE
'
;
export
const
RECEIVE_MOVE_ISSUE_SUCCESS
=
'
RECEIVE_
MOVE_ISSUE_SUCCESS
'
;
export
const
RECEIVE_MOVE_ISSUE_ERROR
=
'
RECEIVE_MOVE_ISSUE_ERROR
'
;
export
const
MOVE_ISSUE
=
'
MOVE_ISSUE
'
;
export
const
MOVE_ISSUE_SUCCESS
=
'
MOVE_ISSUE_SUCCESS
'
;
export
const
MOVE_ISSUE_FAILURE
=
'
MOVE_ISSUE_FAILURE
'
;
export
const
REQUEST_UPDATE_ISSUE
=
'
REQUEST_UPDATE_ISSUE
'
;
export
const
RECEIVE_UPDATE_ISSUE_SUCCESS
=
'
RECEIVE_UPDATE_ISSUE_SUCCESS
'
;
export
const
RECEIVE_UPDATE_ISSUE_ERROR
=
'
RECEIVE_UPDATE_ISSUE_ERROR
'
;
...
...
app/assets/javascripts/boards/stores/mutations.js
View file @
b5a490db
import
Vue
from
'
vue
'
;
import
{
sortBy
,
pull
}
from
'
lodash
'
;
import
{
formatIssue
,
moveIssueListHelper
}
from
'
../boards_util
'
;
import
*
as
mutationTypes
from
'
./mutation_types
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
const
notImplemented
=
()
=>
{
/* eslint-disable-next-line @gitlab/require-i18n-strings */
...
...
@@ -12,6 +14,18 @@ const removeIssueFromList = (state, listId, issueId) => {
Vue
.
set
(
state
.
issuesByListId
,
listId
,
pull
(
state
.
issuesByListId
[
listId
],
issueId
));
};
const
addIssueToList
=
({
state
,
listId
,
issueId
,
moveBeforeId
,
moveAfterId
,
atIndex
})
=>
{
const
listIssues
=
state
.
issuesByListId
[
listId
];
let
newIndex
=
atIndex
||
0
;
if
(
moveBeforeId
)
{
newIndex
=
listIssues
.
indexOf
(
moveBeforeId
)
+
1
;
}
else
if
(
moveAfterId
)
{
newIndex
=
listIssues
.
indexOf
(
moveAfterId
);
}
listIssues
.
splice
(
newIndex
,
0
,
issueId
);
Vue
.
set
(
state
.
issuesByListId
,
listId
,
listIssues
);
};
export
default
{
[
mutationTypes
.
SET_INITIAL_BOARD_DATA
](
state
,
data
)
{
const
{
boardType
,
disabled
,
showPromotion
,
...
endpoints
}
=
data
;
...
...
@@ -111,16 +125,38 @@ export default {
notImplemented
();
},
[
mutationTypes
.
REQUEST_MOVE_ISSUE
]:
()
=>
{
notImplemented
();
[
mutationTypes
.
MOVE_ISSUE
]:
(
state
,
{
originalIssue
,
fromListId
,
toListId
,
moveBeforeId
,
moveAfterId
},
)
=>
{
const
fromList
=
state
.
boardLists
.
find
(
l
=>
l
.
id
===
fromListId
);
const
toList
=
state
.
boardLists
.
find
(
l
=>
l
.
id
===
toListId
);
const
issue
=
moveIssueListHelper
(
originalIssue
,
fromList
,
toList
);
Vue
.
set
(
state
.
issues
,
issue
.
id
,
issue
);
removeIssueFromList
(
state
,
fromListId
,
issue
.
id
);
addIssueToList
({
state
,
listId
:
toListId
,
issueId
:
issue
.
id
,
moveBeforeId
,
moveAfterId
});
},
[
mutationTypes
.
RECEIVE_MOVE_ISSUE_SUCCESS
]:
()
=>
{
notImplemented
();
[
mutationTypes
.
MOVE_ISSUE_SUCCESS
]:
(
state
,
{
issue
})
=>
{
const
issueId
=
getIdFromGraphQLId
(
issue
.
id
);
Vue
.
set
(
state
.
issues
,
issueId
,
formatIssue
({
...
issue
,
id
:
issueId
}));
},
[
mutationTypes
.
RECEIVE_MOVE_ISSUE_ERROR
]:
()
=>
{
notImplemented
();
[
mutationTypes
.
MOVE_ISSUE_FAILURE
]:
(
state
,
{
originalIssue
,
fromListId
,
toListId
,
originalIndex
},
)
=>
{
state
.
error
=
__
(
'
An error occurred while moving the issue. Please try again.
'
);
Vue
.
set
(
state
.
issues
,
originalIssue
.
id
,
originalIssue
);
removeIssueFromList
(
state
,
toListId
,
originalIssue
.
id
);
addIssueToList
({
state
,
listId
:
fromListId
,
issueId
:
originalIssue
.
id
,
atIndex
:
originalIndex
,
});
},
[
mutationTypes
.
REQUEST_UPDATE_ISSUE
]:
()
=>
{
...
...
ee/app/assets/javascripts/boards/components/epic_lane.vue
View file @
b5a490db
...
...
@@ -41,6 +41,11 @@ export default {
type
:
String
,
required
:
true
,
},
canAdminList
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
...
...
@@ -155,6 +160,7 @@ export default {
:root-path=
"rootPath"
:epic-id=
"epic.id"
:epic-is-confidential=
"epic.confidential"
:can-admin-list=
"canAdminList"
/>
</div>
</div>
...
...
ee/app/assets/javascripts/boards/components/epics_swimlanes.vue
View file @
b5a490db
...
...
@@ -139,6 +139,7 @@ export default {
:is-loading-issues=
"isLoadingIssues"
:disabled=
"disabled"
:root-path=
"rootPath"
:can-admin-list=
"canAdminList"
/>
<div
class=
"board-lane-unassigned-issues-title gl-sticky gl-display-inline-block gl-left-0"
>
<div
class=
"gl-left-0 gl-py-5 gl-px-3 gl-display-flex gl-align-items-center"
>
...
...
@@ -171,6 +172,7 @@ export default {
:is-loading="isLoadingIssues"
:disabled="disabled"
:root-path="rootPath"
:can-admin-list="canAdminList"
/>
</div>
</div>
...
...
ee/app/assets/javascripts/boards/components/issues_lane_list.vue
View file @
b5a490db
<
script
>
import
Draggable
from
'
vuedraggable
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
defaultSortableConfig
from
'
~/sortable/sortable_config
'
;
import
BoardCardLayout
from
'
~/boards/components/board_card_layout.vue
'
;
import
eventHub
from
'
~/boards/eventhub
'
;
import
BoardNewIssue
from
'
~/boards/components/board_new_issue.vue
'
;
...
...
@@ -45,6 +47,11 @@ export default {
type
:
String
,
required
:
true
,
},
canAdminList
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
...
...
@@ -53,6 +60,22 @@ export default {
},
computed
:
{
...
mapState
([
'
activeId
'
]),
treeRootWrapper
()
{
return
this
.
canAdminList
?
Draggable
:
'
ul
'
;
},
treeRootOptions
()
{
const
options
=
{
...
defaultSortableConfig
,
fallbackOnBody
:
false
,
group
:
'
board-epics-swimlanes
'
,
tag
:
'
ul
'
,
'
ghost-class
'
:
'
board-card-drag-active
'
,
'
data-list-id
'
:
this
.
list
.
id
,
value
:
this
.
issues
,
};
return
this
.
canAdminList
?
options
:
{};
},
},
created
()
{
eventHub
.
$on
(
`toggle-issue-form-
${
this
.
list
.
id
}
`
,
this
.
toggleForm
);
...
...
@@ -61,7 +84,7 @@ export default {
eventHub
.
$off
(
`toggle-issue-form-
${
this
.
list
.
id
}
`
,
this
.
toggleForm
);
},
methods
:
{
...
mapActions
([
'
setActiveId
'
]),
...
mapActions
([
'
setActiveId
'
,
'
moveIssue
'
]),
toggleForm
()
{
this
.
showIssueForm
=
!
this
.
showIssueForm
;
if
(
this
.
showIssueForm
&&
this
.
isUnassignedIssuesLane
)
{
...
...
@@ -74,6 +97,46 @@ export default {
showIssue
(
issue
)
{
this
.
setActiveId
({
id
:
issue
.
id
,
sidebarType
:
ISSUABLE
});
},
handleDragOnEnd
(
params
)
{
const
{
newIndex
,
oldIndex
,
from
,
to
,
item
}
=
params
;
const
{
issueId
,
issueIid
,
issuePath
}
=
item
.
dataset
;
const
{
children
}
=
to
;
let
moveBeforeId
;
let
moveAfterId
;
// If issue is being moved within the same list
if
(
from
===
to
)
{
if
(
newIndex
>
oldIndex
)
{
// If issue is being moved down we look for the issue that ends up before
moveBeforeId
=
Number
(
children
[
newIndex
].
dataset
.
issueId
);
}
else
if
(
newIndex
<
oldIndex
)
{
// If issue is being moved up we look for the issue that ends up after
moveAfterId
=
Number
(
children
[
newIndex
].
dataset
.
issueId
);
}
else
{
// If issue remains in the same list at the same position we do nothing
return
;
}
}
else
{
// We look for the issue that ends up before the moved issue if it exists
if
(
children
[
newIndex
-
1
])
{
moveBeforeId
=
Number
(
children
[
newIndex
-
1
].
dataset
.
issueId
);
}
// We look for the issue that ends up after the moved issue if it exists
if
(
children
[
newIndex
])
{
moveAfterId
=
Number
(
children
[
newIndex
].
dataset
.
issueId
);
}
}
this
.
moveIssue
({
issueId
,
issueIid
,
issuePath
,
fromListId
:
from
.
dataset
.
listId
,
toListId
:
to
.
dataset
.
listId
,
moveBeforeId
,
moveAfterId
,
});
},
},
};
</
script
>
...
...
@@ -90,7 +153,13 @@ export default {
:group-id=
"groupId"
:list=
"list"
/>
<ul
v-if=
"list.isExpanded"
class=
"gl-p-2 gl-m-0"
>
<component
:is=
"treeRootWrapper"
v-if=
"list.isExpanded"
v-bind=
"treeRootOptions"
class=
"gl-p-2 gl-m-0"
@
end=
"handleDragOnEnd"
>
<board-card-layout
v-for=
"(issue, index) in issues"
ref=
"issue"
...
...
@@ -102,7 +171,7 @@ export default {
:is-active=
"isActiveIssue(issue)"
@
show=
"showIssue(issue)"
/>
</
ul
>
</
component
>
</div>
</div>
</
template
>
locale/gitlab.pot
View file @
b5a490db
...
...
@@ -2828,6 +2828,9 @@ msgstr ""
msgid "An error occurred while moving the issue."
msgstr ""
msgid "An error occurred while moving the issue. Please try again."
msgstr ""
msgid "An error occurred while parsing recent searches"
msgstr ""
...
...
spec/frontend/boards/mock_data.js
View file @
b5a490db
/* global ListIssue */
/* global List */
import
Vue
from
'
vue
'
;
import
List
from
'
~/boards/models/list
'
;
import
'
~/boards/models/list
'
;
import
'
~/boards/models/issue
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
export
const
boardObj
=
{
...
...
@@ -94,11 +98,40 @@ export const mockMilestone = {
due_date
:
'
2019-12-31
'
,
};
export
const
rawIssue
=
{
title
:
'
Testing
'
,
id
:
'
gid://gitlab/Issue/1
'
,
iid
:
1
,
confidential
:
false
,
referencePath
:
'
gitlab-org/gitlab-test#1
'
,
labels
:
{
nodes
:
[
{
id
:
1
,
title
:
'
test
'
,
color
:
'
red
'
,
description
:
'
testing
'
,
},
],
},
assignees
:
{
nodes
:
[
{
id
:
1
,
name
:
'
name
'
,
username
:
'
username
'
,
avatar_url
:
'
http://avatar_url
'
,
},
],
},
};
export
const
mockIssue
=
{
title
:
'
Testing
'
,
id
:
1
,
iid
:
1
,
confidential
:
false
,
referencePath
:
'
gitlab-org/gitlab-test#1
'
,
labels
:
[
{
id
:
1
,
...
...
@@ -117,11 +150,14 @@ export const mockIssue = {
],
};
export
const
mockIssueWithModel
=
new
ListIssue
(
mockIssue
);
export
const
mockIssue2
=
{
title
:
'
Planning
'
,
id
:
2
,
iid
:
2
,
confidential
:
false
,
referencePath
:
'
gitlab-org/gitlab-test#2
'
,
labels
:
[
{
id
:
1
,
...
...
@@ -140,6 +176,8 @@ export const mockIssue2 = {
],
};
export
const
mockIssue2WithModel
=
new
ListIssue
(
mockIssue2
);
export
const
BoardsMockData
=
{
GET
:
{
'
/test/-/boards/1/lists/300/issues?id=300&page=1
'
:
{
...
...
spec/frontend/boards/stores/actions_spec.js
View file @
b5a490db
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
{
mockListsWithModel
,
mockLists
,
mockIssue
}
from
'
../mock_data
'
;
import
{
mockListsWithModel
,
mockLists
,
mockIssue
,
mockIssue2
,
mockIssueWithModel
,
mockIssue2WithModel
,
rawIssue
,
}
from
'
../mock_data
'
;
import
actions
,
{
gqlClient
}
from
'
~/boards/stores/actions
'
;
import
*
as
types
from
'
~/boards/stores/mutation_types
'
;
import
{
inactiveId
,
ListType
}
from
'
~/boards/constants
'
;
...
...
@@ -229,7 +237,107 @@ describe('fetchIssuesForList', () => {
});
describe
(
'
moveIssue
'
,
()
=>
{
expectNotImplemented
(
actions
.
moveIssue
);
const
listIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
,
mockIssue2
.
id
],
'
gid://gitlab/List/2
'
:
[],
};
const
issues
=
{
'
1
'
:
mockIssueWithModel
,
'
2
'
:
mockIssue2WithModel
,
};
const
state
=
{
endpoints
:
{
fullPath
:
'
gitlab-org
'
,
boardId
:
'
1
'
},
boardType
:
'
group
'
,
disabled
:
false
,
boardLists
:
mockListsWithModel
,
issuesByListId
:
listIssues
,
issues
,
};
it
(
'
should commit MOVE_ISSUE mutation and MOVE_ISSUE_SUCCESS mutation when successful
'
,
done
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
issueMoveList
:
{
issue
:
rawIssue
,
errors
:
[],
},
},
});
testAction
(
actions
.
moveIssue
,
{
issueId
:
mockIssue
.
id
,
issueIid
:
mockIssue
.
iid
,
issuePath
:
mockIssue
.
referencePath
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
},
state
,
[
{
type
:
types
.
MOVE_ISSUE
,
payload
:
{
originalIssue
:
mockIssueWithModel
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
},
},
{
type
:
types
.
MOVE_ISSUE_SUCCESS
,
payload
:
{
issue
:
rawIssue
},
},
],
[],
done
,
);
});
it
(
'
should commit MOVE_ISSUE mutation and MOVE_ISSUE_FAILURE mutation when unsuccessful
'
,
done
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
issueMoveList
:
{
issue
:
{},
errors
:
[{
foo
:
'
bar
'
}],
},
},
});
testAction
(
actions
.
moveIssue
,
{
issueId
:
mockIssue
.
id
,
issueIid
:
mockIssue
.
iid
,
issuePath
:
mockIssue
.
referencePath
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
},
state
,
[
{
type
:
types
.
MOVE_ISSUE
,
payload
:
{
originalIssue
:
mockIssueWithModel
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
},
},
{
type
:
types
.
MOVE_ISSUE_FAILURE
,
payload
:
{
originalIssue
:
mockIssueWithModel
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
originalIndex
:
0
,
},
},
],
[],
done
,
);
});
});
describe
(
'
createNewIssue
'
,
()
=>
{
...
...
spec/frontend/boards/stores/mutations_spec.js
View file @
b5a490db
...
...
@@ -4,10 +4,13 @@ import defaultState from '~/boards/stores/state';
import
{
listObj
,
listObjDuplicate
,
mockIssue
,
mockIssue2
,
mockListsWithModel
,
mockLists
,
rawIssue
,
mockIssue
,
mockIssue2
,
mockIssueWithModel
,
mockIssue2WithModel
,
}
from
'
../mock_data
'
;
const
expectNotImplemented
=
action
=>
{
...
...
@@ -247,16 +250,86 @@ describe('Board Store Mutations', () => {
expectNotImplemented
(
mutations
.
RECEIVE_ADD_ISSUE_ERROR
);
});
describe
(
'
REQUEST_MOVE_ISSUE
'
,
()
=>
{
expectNotImplemented
(
mutations
.
REQUEST_MOVE_ISSUE
);
describe
(
'
MOVE_ISSUE
'
,
()
=>
{
it
(
'
updates issuesByListId, moving issue between lists
'
,
()
=>
{
const
listIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
,
mockIssue2
.
id
],
'
gid://gitlab/List/2
'
:
[],
};
const
issues
=
{
'
1
'
:
mockIssueWithModel
,
'
2
'
:
mockIssue2WithModel
,
};
state
=
{
...
state
,
issuesByListId
:
listIssues
,
boardLists
:
mockListsWithModel
,
issues
,
};
mutations
.
MOVE_ISSUE
(
state
,
{
originalIssue
:
mockIssue2WithModel
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
});
const
updatedListIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
],
'
gid://gitlab/List/2
'
:
[
mockIssue2
.
id
],
};
expect
(
state
.
issuesByListId
).
toEqual
(
updatedListIssues
);
});
});
describe
(
'
MOVE_ISSUE_SUCCESS
'
,
()
=>
{
it
(
'
updates issue in issues state
'
,
()
=>
{
const
issues
=
{
'
1
'
:
{
id
:
rawIssue
.
id
},
};
state
=
{
...
state
,
issues
,
};
mutations
.
MOVE_ISSUE_SUCCESS
(
state
,
{
issue
:
rawIssue
,
});
describe
(
'
RECEIVE_MOVE_ISSUE_SUCCESS
'
,
()
=>
{
expectNotImplemented
(
mutations
.
RECEIVE_MOVE_ISSUE_SUCCESS
);
expect
(
state
.
issues
).
toEqual
({
'
1
'
:
{
...
mockIssueWithModel
,
id
:
1
}
});
}
);
});
describe
(
'
RECEIVE_MOVE_ISSUE_ERROR
'
,
()
=>
{
expectNotImplemented
(
mutations
.
RECEIVE_MOVE_ISSUE_ERROR
);
describe
(
'
MOVE_ISSUE_FAILURE
'
,
()
=>
{
it
(
'
updates issuesByListId, reverting moving issue between lists, and sets error message
'
,
()
=>
{
const
listIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
],
'
gid://gitlab/List/2
'
:
[
mockIssue2
.
id
],
};
state
=
{
...
state
,
issuesByListId
:
listIssues
,
};
mutations
.
MOVE_ISSUE_FAILURE
(
state
,
{
originalIssue
:
mockIssue2
,
fromListId
:
'
gid://gitlab/List/1
'
,
toListId
:
'
gid://gitlab/List/2
'
,
originalIndex
:
1
,
});
const
updatedListIssues
=
{
'
gid://gitlab/List/1
'
:
[
mockIssue
.
id
,
mockIssue2
.
id
],
'
gid://gitlab/List/2
'
:
[],
};
expect
(
state
.
issuesByListId
).
toEqual
(
updatedListIssues
);
expect
(
state
.
error
).
toEqual
(
'
An error occurred while moving the issue. Please try again.
'
);
});
});
describe
(
'
REQUEST_UPDATE_ISSUE
'
,
()
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment