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
3a172309
Commit
3a172309
authored
Mar 11, 2021
by
Simon Knox
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'psiassignee' into 'master'
Boards new list for Assignee See merge request gitlab-org/gitlab!56151
parents
e6a9a479
9828565d
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
335 additions
and
29 deletions
+335
-29
ee/app/assets/javascripts/boards/components/board_add_new_column.vue
...ts/javascripts/boards/components/board_add_new_column.vue
+65
-4
ee/app/assets/javascripts/boards/graphql/group_board_assignees.query.graphql
...cripts/boards/graphql/group_board_assignees.query.graphql
+16
-0
ee/app/assets/javascripts/boards/graphql/project_board_assignees.query.graphql
...ipts/boards/graphql/project_board_assignees.query.graphql
+16
-0
ee/app/assets/javascripts/boards/stores/actions.js
ee/app/assets/javascripts/boards/stores/actions.js
+48
-0
ee/app/assets/javascripts/boards/stores/mutation_types.js
ee/app/assets/javascripts/boards/stores/mutation_types.js
+3
-0
ee/app/assets/javascripts/boards/stores/mutations.js
ee/app/assets/javascripts/boards/stores/mutations.js
+14
-0
ee/app/assets/javascripts/boards/stores/state.js
ee/app/assets/javascripts/boards/stores/state.js
+2
-0
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
+22
-15
ee/spec/frontend/boards/components/board_add_new_column_spec.js
...c/frontend/boards/components/board_add_new_column_spec.js
+44
-3
ee/spec/frontend/boards/mock_data.js
ee/spec/frontend/boards/mock_data.js
+13
-6
ee/spec/frontend/boards/stores/actions_spec.js
ee/spec/frontend/boards/stores/actions_spec.js
+83
-1
locale/gitlab.pot
locale/gitlab.pot
+9
-0
No files found.
ee/app/assets/javascripts/boards/components/board_add_new_column.vue
View file @
3a172309
<
script
>
<
script
>
import
{
import
{
GlAvatarLabeled
,
GlFormGroup
,
GlFormGroup
,
GlFormRadio
,
GlFormRadio
,
GlFormRadioGroup
,
GlFormRadioGroup
,
...
@@ -19,18 +20,23 @@ export default {
...
@@ -19,18 +20,23 @@ export default {
i18n
:
{
i18n
:
{
listType
:
__
(
'
List type
'
),
listType
:
__
(
'
List type
'
),
labelListDescription
:
__
(
'
A label list displays issues with the selected label.
'
),
labelListDescription
:
__
(
'
A label list displays issues with the selected label.
'
),
assigneeListDescription
:
__
(
'
An assignee list displays issues assigned to the selected user
'
),
milestoneListDescription
:
__
(
'
A milestone list displays issues in the selected milestone.
'
),
milestoneListDescription
:
__
(
'
A milestone list displays issues in the selected milestone.
'
),
selectLabel
:
__
(
'
Select label
'
),
selectLabel
:
__
(
'
Select label
'
),
selectAssignee
:
__
(
'
Select assignee
'
),
selectMilestone
:
__
(
'
Select milestone
'
),
selectMilestone
:
__
(
'
Select milestone
'
),
searchLabels
:
__
(
'
Search labels
'
),
searchLabels
:
__
(
'
Search labels
'
),
searchAssignees
:
__
(
'
Search assignees
'
),
searchMilestones
:
__
(
'
Search milestones
'
),
searchMilestones
:
__
(
'
Search milestones
'
),
},
},
columnTypes
:
[
columnTypes
:
[
{
value
:
ListType
.
label
,
text
:
__
(
'
Label
'
)
},
{
value
:
ListType
.
label
,
text
:
__
(
'
Label
'
)
},
{
value
:
ListType
.
assignee
,
text
:
__
(
'
Assignee
'
)
},
{
value
:
ListType
.
milestone
,
text
:
__
(
'
Milestone
'
)
},
{
value
:
ListType
.
milestone
,
text
:
__
(
'
Milestone
'
)
},
],
],
components
:
{
components
:
{
BoardAddNewColumnForm
,
BoardAddNewColumnForm
,
GlAvatarLabeled
,
GlFormGroup
,
GlFormGroup
,
GlFormRadio
,
GlFormRadio
,
GlFormRadioGroup
,
GlFormRadioGroup
,
...
@@ -48,13 +54,23 @@ export default {
...
@@ -48,13 +54,23 @@ export default {
};
};
},
},
computed
:
{
computed
:
{
...
mapState
([
'
labels
'
,
'
labelsLoading
'
,
'
milestones
'
,
'
milestonesLoading
'
]),
...
mapState
([
'
labels
'
,
'
labelsLoading
'
,
'
assignees
'
,
'
assigneesLoading
'
,
'
milestones
'
,
'
milestonesLoading
'
,
]),
...
mapGetters
([
'
getListByTypeId
'
,
'
shouldUseGraphQL
'
,
'
isEpicBoard
'
]),
...
mapGetters
([
'
getListByTypeId
'
,
'
shouldUseGraphQL
'
,
'
isEpicBoard
'
]),
items
()
{
items
()
{
if
(
this
.
labelTypeSelected
)
{
if
(
this
.
labelTypeSelected
)
{
return
this
.
labels
;
return
this
.
labels
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
assignees
;
}
if
(
this
.
milestoneTypeSelected
)
{
if
(
this
.
milestoneTypeSelected
)
{
return
this
.
milestones
;
return
this
.
milestones
;
}
}
...
@@ -64,6 +80,9 @@ export default {
...
@@ -64,6 +80,9 @@ export default {
labelTypeSelected
()
{
labelTypeSelected
()
{
return
this
.
columnType
===
ListType
.
label
;
return
this
.
columnType
===
ListType
.
label
;
},
},
assigneeTypeSelected
()
{
return
this
.
columnType
===
ListType
.
assignee
;
},
milestoneTypeSelected
()
{
milestoneTypeSelected
()
{
return
this
.
columnType
===
ListType
.
milestone
;
return
this
.
columnType
===
ListType
.
milestone
;
},
},
...
@@ -74,6 +93,12 @@ export default {
...
@@ -74,6 +93,12 @@ export default {
}
}
return
this
.
labels
.
find
(({
id
})
=>
id
===
this
.
selectedId
);
return
this
.
labels
.
find
(({
id
})
=>
id
===
this
.
selectedId
);
},
},
selectedAssignee
()
{
if
(
!
this
.
assigneeTypeSelected
)
{
return
null
;
}
return
this
.
assignees
.
find
(({
id
})
=>
id
===
this
.
selectedId
);
},
selectedMilestone
()
{
selectedMilestone
()
{
if
(
!
this
.
milestoneTypeSelected
)
{
if
(
!
this
.
milestoneTypeSelected
)
{
return
null
;
return
null
;
...
@@ -87,6 +112,9 @@ export default {
...
@@ -87,6 +112,9 @@ export default {
if
(
this
.
labelTypeSelected
)
{
if
(
this
.
labelTypeSelected
)
{
return
this
.
selectedLabel
;
return
this
.
selectedLabel
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
selectedAssignee
;
}
if
(
this
.
milestoneTypeSelected
)
{
if
(
this
.
milestoneTypeSelected
)
{
return
this
.
selectedMilestone
;
return
this
.
selectedMilestone
;
}
}
...
@@ -108,6 +136,9 @@ export default {
...
@@ -108,6 +136,9 @@ export default {
if
(
this
.
columnType
===
ListType
.
label
)
{
if
(
this
.
columnType
===
ListType
.
label
)
{
return
this
.
labelsLoading
;
return
this
.
labelsLoading
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
assigneesLoading
;
}
if
(
this
.
columnType
===
ListType
.
milestone
)
{
if
(
this
.
columnType
===
ListType
.
milestone
)
{
return
this
.
milestonesLoading
;
return
this
.
milestonesLoading
;
}
}
...
@@ -119,6 +150,10 @@ export default {
...
@@ -119,6 +150,10 @@ export default {
return
this
.
$options
.
i18n
.
labelListDescription
;
return
this
.
$options
.
i18n
.
labelListDescription
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
$options
.
i18n
.
assigneeListDescription
;
}
if
(
this
.
milestoneTypeSelected
)
{
if
(
this
.
milestoneTypeSelected
)
{
return
this
.
$options
.
i18n
.
milestoneListDescription
;
return
this
.
$options
.
i18n
.
milestoneListDescription
;
}
}
...
@@ -131,6 +166,10 @@ export default {
...
@@ -131,6 +166,10 @@ export default {
return
this
.
$options
.
i18n
.
selectLabel
;
return
this
.
$options
.
i18n
.
selectLabel
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
$options
.
i18n
.
selectAssignee
;
}
if
(
this
.
milestoneTypeSelected
)
{
if
(
this
.
milestoneTypeSelected
)
{
return
this
.
$options
.
i18n
.
selectMilestone
;
return
this
.
$options
.
i18n
.
selectMilestone
;
}
}
...
@@ -143,6 +182,10 @@ export default {
...
@@ -143,6 +182,10 @@ export default {
return
this
.
$options
.
i18n
.
searchLabels
;
return
this
.
$options
.
i18n
.
searchLabels
;
}
}
if
(
this
.
assigneeTypeSelected
)
{
return
this
.
$options
.
i18n
.
searchAssignees
;
}
if
(
this
.
milestoneTypeSelected
)
{
if
(
this
.
milestoneTypeSelected
)
{
return
this
.
$options
.
i18n
.
searchMilestones
;
return
this
.
$options
.
i18n
.
searchMilestones
;
}
}
...
@@ -159,6 +202,7 @@ export default {
...
@@ -159,6 +202,7 @@ export default {
'
fetchLabels
'
,
'
fetchLabels
'
,
'
highlightList
'
,
'
highlightList
'
,
'
setAddColumnFormVisibility
'
,
'
setAddColumnFormVisibility
'
,
'
fetchAssignees
'
,
'
fetchMilestones
'
,
'
fetchMilestones
'
,
]),
]),
highlight
(
listId
)
{
highlight
(
listId
)
{
...
@@ -206,6 +250,11 @@ export default {
...
@@ -206,6 +250,11 @@ export default {
...
this
.
selectedMilestone
,
...
this
.
selectedMilestone
,
id
:
getIdFromGraphQLId
(
this
.
selectedMilestone
.
id
),
id
:
getIdFromGraphQLId
(
this
.
selectedMilestone
.
id
),
};
};
}
else
if
(
this
.
assigneeTypeSelected
)
{
listObj
.
assignee
=
{
...
this
.
selectedAssignee
,
id
:
getIdFromGraphQLId
(
this
.
selectedAssignee
.
id
),
};
}
}
boardsStore
.
new
(
listObj
);
boardsStore
.
new
(
listObj
);
...
@@ -217,6 +266,9 @@ export default {
...
@@ -217,6 +266,9 @@ export default {
case
ListType
.
milestone
:
case
ListType
.
milestone
:
this
.
fetchMilestones
(
searchTerm
);
this
.
fetchMilestones
(
searchTerm
);
break
;
break
;
case
ListType
.
assignee
:
this
.
fetchAssignees
(
searchTerm
);
break
;
case
ListType
.
label
:
case
ListType
.
label
:
default
:
default
:
this
.
fetchLabels
(
searchTerm
);
this
.
fetchLabels
(
searchTerm
);
...
@@ -227,7 +279,8 @@ export default {
...
@@ -227,7 +279,8 @@ export default {
return
this
.
scopedLabelsAvailable
&&
isScopedLabel
(
label
);
return
this
.
scopedLabelsAvailable
&&
isScopedLabel
(
label
);
},
},
setColumnType
()
{
setColumnType
(
type
)
{
this
.
columnType
=
type
;
this
.
selectedId
=
null
;
this
.
selectedId
=
null
;
this
.
filterItems
();
this
.
filterItems
();
},
},
...
@@ -287,7 +340,7 @@ export default {
...
@@ -287,7 +340,7 @@ export default {
:key=
"item.id"
:key=
"item.id"
class=
"gl-display-flex gl-flex-align-items-center gl-mb-5 gl-font-weight-normal"
class=
"gl-display-flex gl-flex-align-items-center gl-mb-5 gl-font-weight-normal"
>
>
<gl-form-radio
:value=
"item.id"
class=
"gl-mb-0"
/>
<gl-form-radio
:value=
"item.id"
class=
"gl-mb-0
gl-align-self-center
"
/>
<span
<span
v-if=
"labelTypeSelected"
v-if=
"labelTypeSelected"
class=
"dropdown-label-box gl-top-0"
class=
"dropdown-label-box gl-top-0"
...
@@ -295,7 +348,15 @@ export default {
...
@@ -295,7 +348,15 @@ export default {
backgroundColor: item.color,
backgroundColor: item.color,
}"
}"
>
</span>
>
</span>
<span>
{{
item
.
title
}}
</span>
<gl-avatar-labeled
v-if=
"assigneeTypeSelected"
:size=
"32"
:label=
"item.name"
:sub-label=
"item.username"
:src=
"item.avatarUrl"
/>
<span
v-else
>
{{
item
.
title
}}
</span>
</label>
</label>
</gl-form-radio-group>
</gl-form-radio-group>
</
template
>
</
template
>
...
...
ee/app/assets/javascripts/boards/graphql/group_board_assignees.query.graphql
0 → 100644
View file @
3a172309
#import "~/graphql_shared/fragments/user.fragment.graphql"
query
GroupBoardAssignees
(
$fullPath
:
ID
!,
$search
:
String
)
{
workspace
:
group
(
fullPath
:
$fullPath
)
{
__typename
assignees
:
groupMembers
(
search
:
$search
)
{
__typename
nodes
{
id
user
{
...
User
}
}
}
}
}
ee/app/assets/javascripts/boards/graphql/project_board_assignees.query.graphql
0 → 100644
View file @
3a172309
#import "~/graphql_shared/fragments/user.fragment.graphql"
query
ProjectBoardAssignees
(
$fullPath
:
ID
!,
$search
:
String
)
{
workspace
:
project
(
fullPath
:
$fullPath
)
{
__typename
assignees
:
projectMembers
(
search
:
$search
)
{
__typename
nodes
{
id
user
{
...
User
}
}
}
}
}
ee/app/assets/javascripts/boards/stores/actions.js
View file @
3a172309
...
@@ -34,12 +34,14 @@ import createEpicBoardListMutation from '../graphql/epic_board_list_create.mutat
...
@@ -34,12 +34,14 @@ import createEpicBoardListMutation from '../graphql/epic_board_list_create.mutat
import
epicBoardListsQuery
from
'
../graphql/epic_board_lists.query.graphql
'
;
import
epicBoardListsQuery
from
'
../graphql/epic_board_lists.query.graphql
'
;
import
epicMoveListMutation
from
'
../graphql/epic_move_list.mutation.graphql
'
;
import
epicMoveListMutation
from
'
../graphql/epic_move_list.mutation.graphql
'
;
import
epicsSwimlanesQuery
from
'
../graphql/epics_swimlanes.query.graphql
'
;
import
epicsSwimlanesQuery
from
'
../graphql/epics_swimlanes.query.graphql
'
;
import
groupBoardAssigneesQuery
from
'
../graphql/group_board_assignees.query.graphql
'
;
import
groupBoardMilestonesQuery
from
'
../graphql/group_board_milestones.query.graphql
'
;
import
groupBoardMilestonesQuery
from
'
../graphql/group_board_milestones.query.graphql
'
;
import
issueMoveListMutation
from
'
../graphql/issue_move_list.mutation.graphql
'
;
import
issueMoveListMutation
from
'
../graphql/issue_move_list.mutation.graphql
'
;
import
issueSetEpicMutation
from
'
../graphql/issue_set_epic.mutation.graphql
'
;
import
issueSetEpicMutation
from
'
../graphql/issue_set_epic.mutation.graphql
'
;
import
issueSetWeightMutation
from
'
../graphql/issue_set_weight.mutation.graphql
'
;
import
issueSetWeightMutation
from
'
../graphql/issue_set_weight.mutation.graphql
'
;
import
listUpdateLimitMetricsMutation
from
'
../graphql/list_update_limit_metrics.mutation.graphql
'
;
import
listUpdateLimitMetricsMutation
from
'
../graphql/list_update_limit_metrics.mutation.graphql
'
;
import
listsEpicsQuery
from
'
../graphql/lists_epics.query.graphql
'
;
import
listsEpicsQuery
from
'
../graphql/lists_epics.query.graphql
'
;
import
projectBoardAssigneesQuery
from
'
../graphql/project_board_assignees.query.graphql
'
;
import
projectBoardMilestonesQuery
from
'
../graphql/project_board_milestones.query.graphql
'
;
import
projectBoardMilestonesQuery
from
'
../graphql/project_board_milestones.query.graphql
'
;
import
updateBoardEpicUserPreferencesMutation
from
'
../graphql/update_board_epic_user_preferences.mutation.graphql
'
;
import
updateBoardEpicUserPreferencesMutation
from
'
../graphql/update_board_epic_user_preferences.mutation.graphql
'
;
...
@@ -646,6 +648,52 @@ export default {
...
@@ -646,6 +648,52 @@ export default {
});
});
},
},
fetchAssignees
({
state
,
commit
},
search
)
{
commit
(
types
.
RECEIVE_ASSIGNEES_REQUEST
);
const
{
fullPath
,
boardType
}
=
state
;
const
variables
=
{
fullPath
,
search
,
};
let
query
;
if
(
boardType
===
BoardType
.
project
)
{
query
=
projectBoardAssigneesQuery
;
}
if
(
boardType
===
BoardType
.
group
)
{
query
=
groupBoardAssigneesQuery
;
}
if
(
!
query
)
{
// eslint-disable-next-line @gitlab/require-i18n-strings
throw
new
Error
(
'
Unknown board type
'
);
}
return
gqlClient
.
query
({
query
,
variables
,
})
.
then
(({
data
})
=>
{
const
[
firstError
]
=
data
.
workspace
.
errors
||
[];
const
assignees
=
data
.
workspace
.
assignees
.
nodes
;
if
(
firstError
)
{
throw
new
Error
(
firstError
);
}
commit
(
types
.
RECEIVE_ASSIGNEES_SUCCESS
,
assignees
.
map
(({
user
})
=>
user
),
);
})
.
catch
((
e
)
=>
{
commit
(
types
.
RECEIVE_ASSIGNEES_FAILURE
);
throw
e
;
});
},
createList
:
({
getters
,
dispatch
},
{
backlog
,
labelId
,
milestoneId
,
assigneeId
})
=>
{
createList
:
({
getters
,
dispatch
},
{
backlog
,
labelId
,
milestoneId
,
assigneeId
})
=>
{
if
(
!
getters
.
isEpicBoard
)
{
if
(
!
getters
.
isEpicBoard
)
{
dispatch
(
'
createIssueList
'
,
{
backlog
,
labelId
,
milestoneId
,
assigneeId
});
dispatch
(
'
createIssueList
'
,
{
backlog
,
labelId
,
milestoneId
,
assigneeId
});
...
...
ee/app/assets/javascripts/boards/stores/mutation_types.js
View file @
3a172309
...
@@ -38,3 +38,6 @@ export const SET_BOARD_EPIC_USER_PREFERENCES = 'SET_BOARD_EPIC_USER_PREFERENCES'
...
@@ -38,3 +38,6 @@ export const SET_BOARD_EPIC_USER_PREFERENCES = 'SET_BOARD_EPIC_USER_PREFERENCES'
export
const
RECEIVE_MILESTONES_REQUEST
=
'
RECEIVE_MILESTONES_REQUEST
'
;
export
const
RECEIVE_MILESTONES_REQUEST
=
'
RECEIVE_MILESTONES_REQUEST
'
;
export
const
RECEIVE_MILESTONES_SUCCESS
=
'
RECEIVE_MILESTONES_SUCCESS
'
;
export
const
RECEIVE_MILESTONES_SUCCESS
=
'
RECEIVE_MILESTONES_SUCCESS
'
;
export
const
RECEIVE_MILESTONES_FAILURE
=
'
RECEIVE_MILESTONES_FAILURE
'
;
export
const
RECEIVE_MILESTONES_FAILURE
=
'
RECEIVE_MILESTONES_FAILURE
'
;
export
const
RECEIVE_ASSIGNEES_REQUEST
=
'
RECEIVE_ASSIGNEES_REQUEST
'
;
export
const
RECEIVE_ASSIGNEES_SUCCESS
=
'
RECEIVE_ASSIGNEES_SUCCESS
'
;
export
const
RECEIVE_ASSIGNEES_FAILURE
=
'
RECEIVE_ASSIGNEES_FAILURE
'
;
ee/app/assets/javascripts/boards/stores/mutations.js
View file @
3a172309
...
@@ -232,4 +232,18 @@ export default {
...
@@ -232,4 +232,18 @@ export default {
state
.
milestonesLoading
=
false
;
state
.
milestonesLoading
=
false
;
state
.
error
=
__
(
'
Failed to load milestones.
'
);
state
.
error
=
__
(
'
Failed to load milestones.
'
);
},
},
[
mutationTypes
.
RECEIVE_ASSIGNEES_REQUEST
](
state
)
{
state
.
assigneesLoading
=
true
;
},
[
mutationTypes
.
RECEIVE_ASSIGNEES_SUCCESS
](
state
,
assignees
)
{
state
.
assignees
=
assignees
;
state
.
assigneesLoading
=
false
;
},
[
mutationTypes
.
RECEIVE_ASSIGNEES_FAILURE
](
state
)
{
state
.
assigneesLoading
=
false
;
state
.
error
=
__
(
'
Failed to load assignees.
'
);
},
};
};
ee/app/assets/javascripts/boards/stores/state.js
View file @
3a172309
...
@@ -14,4 +14,6 @@ export default () => ({
...
@@ -14,4 +14,6 @@ export default () => ({
epicsFlags
:
{},
epicsFlags
:
{},
milestones
:
[],
milestones
:
[],
milestonesLoading
:
false
,
milestonesLoading
:
false
,
assignees
:
[],
assigneesLoading
:
false
,
});
});
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
View file @
3a172309
...
@@ -15,7 +15,8 @@ RSpec.describe 'User adds milestone lists', :js do
...
@@ -15,7 +15,8 @@ RSpec.describe 'User adds milestone lists', :js do
let_it_be
(
:group_backlog_list
)
{
create
(
:backlog_list
,
board:
group_board
)
}
let_it_be
(
:group_backlog_list
)
{
create
(
:backlog_list
,
board:
group_board
)
}
let_it_be
(
:issue
)
{
create
(
:issue
,
project:
project
,
milestone:
milestone
)
}
let_it_be
(
:issue_with_milestone
)
{
create
(
:issue
,
project:
project
,
milestone:
milestone
)
}
let_it_be
(
:issue_with_assignee
)
{
create
(
:issue
,
project:
project
,
assignees:
[
user
])
}
before_all
do
before_all
do
project
.
add_maintainer
(
user
)
project
.
add_maintainer
(
user
)
...
@@ -31,7 +32,10 @@ RSpec.describe 'User adds milestone lists', :js do
...
@@ -31,7 +32,10 @@ RSpec.describe 'User adds milestone lists', :js do
with_them
do
with_them
do
before
do
before
do
stub_licensed_features
(
board_milestone_lists:
true
)
stub_licensed_features
(
board_milestone_lists:
true
,
board_assignee_lists:
true
)
sign_in
(
user
)
sign_in
(
user
)
set_cookie
(
'sidebar_collapsed'
,
'true'
)
set_cookie
(
'sidebar_collapsed'
,
'true'
)
...
@@ -51,28 +55,31 @@ RSpec.describe 'User adds milestone lists', :js do
...
@@ -51,28 +55,31 @@ RSpec.describe 'User adds milestone lists', :js do
end
end
it
'creates milestone column'
do
it
'creates milestone column'
do
click_button
button_text
add_list
(
'Milestone'
,
milestone
.
title
)
wait_for_all_requests
select
(
'Milestone'
,
from:
'List type'
)
add_milestone_list
(
milestone
)
expect
(
page
).
to
have_selector
(
'.board'
,
text:
milestone
.
title
)
expect
(
find
(
'.board:nth-child(2) .board-card'
)).
to
have_content
(
issue_with_milestone
.
title
)
end
wait_for_all_requests
it
'creates assignee column'
do
add_list
(
'Assignee'
,
user
.
name
)
expect
(
page
).
to
have_selector
(
'.board'
,
text:
milestone
.
titl
e
)
expect
(
page
).
to
have_selector
(
'.board'
,
text:
user
.
nam
e
)
expect
(
find
(
'.board:nth-child(2) .board-card'
)).
to
have_content
(
issue
.
title
)
expect
(
find
(
'.board:nth-child(2) .board-card'
)).
to
have_content
(
issue
_with_assignee
.
title
)
end
end
end
end
def
add_milestone_list
(
milestone
)
def
add_list
(
list_type
,
title
)
click_button
'Create list'
wait_for_all_requests
select
(
list_type
,
from:
'List type'
)
page
.
within
(
'.board-add-new-list'
)
do
page
.
within
(
'.board-add-new-list'
)
do
find
(
'label'
,
text:
milestone
.
title
).
click
find
(
'label'
,
text:
title
).
click
click_button
'Add'
click_button
'Add'
end
end
end
def
button_text
wait_for_all_requests
'Create list'
end
end
end
end
ee/spec/frontend/boards/components/board_add_new_column_spec.js
View file @
3a172309
import
{
Gl
SearchBoxByType
}
from
'
@gitlab/ui
'
;
import
{
Gl
AvatarLabeled
,
GlSearchBoxByType
,
GlFormSelect
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
Vuex
from
'
vuex
'
;
import
BoardAddNewColumn
from
'
ee/boards/components/board_add_new_column.vue
'
;
import
BoardAddNewColumn
from
'
ee/boards/components/board_add_new_column.vue
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
BoardAddNewColumnForm
from
'
~/boards/components/board_add_new_column_form.vue
'
;
import
BoardAddNewColumnForm
from
'
~/boards/components/board_add_new_column_form.vue
'
;
import
{
ListType
}
from
'
~/boards/constants
'
;
import
defaultState
from
'
~/boards/stores/state
'
;
import
defaultState
from
'
~/boards/stores/state
'
;
import
{
mockLists
}
from
'
../mock_data
'
;
import
{
mock
Assignees
,
mock
Lists
}
from
'
../mock_data
'
;
const
mockLabelList
=
mockLists
[
1
];
const
mockLabelList
=
mockLists
[
1
];
Vue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
Board
card layout
'
,
()
=>
{
describe
(
'
Board
AddNewColumn
'
,
()
=>
{
let
wrapper
;
let
wrapper
;
let
shouldUseGraphQL
;
let
shouldUseGraphQL
;
...
@@ -30,6 +31,7 @@ describe('Board card layout', () => {
...
@@ -30,6 +31,7 @@ describe('Board card layout', () => {
const
mountComponent
=
({
const
mountComponent
=
({
selectedId
,
selectedId
,
labels
=
[],
labels
=
[],
assignees
=
[],
getListByTypeId
=
jest
.
fn
(),
getListByTypeId
=
jest
.
fn
(),
actions
=
{},
actions
=
{},
}
=
{})
=>
{
}
=
{})
=>
{
...
@@ -57,6 +59,8 @@ describe('Board card layout', () => {
...
@@ -57,6 +59,8 @@ describe('Board card layout', () => {
state
:
{
state
:
{
labels
,
labels
,
labelsLoading
:
false
,
labelsLoading
:
false
,
assignees
,
assigneesLoading
:
false
,
},
},
}),
}),
provide
:
{
provide
:
{
...
@@ -71,10 +75,12 @@ describe('Board card layout', () => {
...
@@ -71,10 +75,12 @@ describe('Board card layout', () => {
wrapper
=
null
;
wrapper
=
null
;
});
});
const
findForm
=
()
=>
wrapper
.
findComponent
(
BoardAddNewColumnForm
);
const
formTitle
=
()
=>
wrapper
.
findByTestId
(
'
board-add-column-form-title
'
).
text
();
const
formTitle
=
()
=>
wrapper
.
findByTestId
(
'
board-add-column-form-title
'
).
text
();
const
findSearchInput
=
()
=>
wrapper
.
find
(
GlSearchBoxByType
);
const
findSearchInput
=
()
=>
wrapper
.
find
(
GlSearchBoxByType
);
const
cancelButton
=
()
=>
wrapper
.
findByTestId
(
'
cancelAddNewColumn
'
);
const
cancelButton
=
()
=>
wrapper
.
findByTestId
(
'
cancelAddNewColumn
'
);
const
submitButton
=
()
=>
wrapper
.
findByTestId
(
'
addNewColumnButton
'
);
const
submitButton
=
()
=>
wrapper
.
findByTestId
(
'
addNewColumnButton
'
);
const
listTypeSelect
=
()
=>
wrapper
.
findComponent
(
GlFormSelect
);
beforeEach
(()
=>
{
beforeEach
(()
=>
{
shouldUseGraphQL
=
true
;
shouldUseGraphQL
=
true
;
...
@@ -152,4 +158,39 @@ describe('Board card layout', () => {
...
@@ -152,4 +158,39 @@ describe('Board card layout', () => {
expect
(
createList
).
not
.
toHaveBeenCalled
();
expect
(
createList
).
not
.
toHaveBeenCalled
();
});
});
});
});
describe
(
'
assignee list
'
,
()
=>
{
beforeEach
(
async
()
=>
{
mountComponent
({
assignees
:
mockAssignees
,
actions
:
{
fetchAssignees
:
jest
.
fn
(),
},
});
listTypeSelect
().
vm
.
$emit
(
'
change
'
,
ListType
.
assignee
);
await
nextTick
();
});
it
(
'
sets assignee placeholder text in form
'
,
async
()
=>
{
expect
(
findForm
().
props
()).
toMatchObject
({
formDescription
:
BoardAddNewColumn
.
i18n
.
assigneeListDescription
,
searchLabel
:
BoardAddNewColumn
.
i18n
.
selectAssignee
,
searchPlaceholder
:
BoardAddNewColumn
.
i18n
.
searchAssignees
,
});
});
it
(
'
shows list of assignees
'
,
()
=>
{
const
userList
=
wrapper
.
findAllComponents
(
GlAvatarLabeled
);
const
[
firstUser
]
=
mockAssignees
;
expect
(
userList
).
toHaveLength
(
mockAssignees
.
length
);
expect
(
userList
.
at
(
0
).
props
()).
toMatchObject
({
label
:
firstUser
.
name
,
subLabel
:
firstUser
.
username
,
});
});
});
});
});
ee/spec/frontend/boards/mock_data.js
View file @
3a172309
...
@@ -76,7 +76,7 @@ const defaultDescendantCounts = {
...
@@ -76,7 +76,7 @@ const defaultDescendantCounts = {
closedIssues
:
0
,
closedIssues
:
0
,
};
};
const
a
ssignees
=
[
export
const
mockA
ssignees
=
[
{
{
id
:
'
gid://gitlab/User/2
'
,
id
:
'
gid://gitlab/User/2
'
,
username
:
'
angelina.herman
'
,
username
:
'
angelina.herman
'
,
...
@@ -84,6 +84,13 @@ const assignees = [
...
@@ -84,6 +84,13 @@ const assignees = [
avatar
:
'
https://www.gravatar.com/avatar/eb7b664b13a30ad9f9ba4b61d7075470?s=80&d=identicon
'
,
avatar
:
'
https://www.gravatar.com/avatar/eb7b664b13a30ad9f9ba4b61d7075470?s=80&d=identicon
'
,
webUrl
:
'
http://127.0.0.1:3000/angelina.herman
'
,
webUrl
:
'
http://127.0.0.1:3000/angelina.herman
'
,
},
},
{
id
:
'
gid://gitlab/User/118
'
,
username
:
'
jacklyn.moore
'
,
name
:
'
Brock Jaskolski
'
,
avatar
:
'
https://www.gravatar.com/avatar/af29c072d9fcf315772cfd802c7a7d35?s=80&d=identicon
'
,
webUrl
:
'
http://127.0.0.1:3000/jacklyn.moore
'
,
},
];
];
export
const
mockMilestones
=
[
export
const
mockMilestones
=
[
...
@@ -127,7 +134,7 @@ export const rawIssue = {
...
@@ -127,7 +134,7 @@ export const rawIssue = {
],
],
},
},
assignees
:
{
assignees
:
{
nodes
:
a
ssignees
,
nodes
:
mockA
ssignees
,
},
},
epic
:
{
epic
:
{
id
:
'
gid://gitlab/Epic/41
'
,
id
:
'
gid://gitlab/Epic/41
'
,
...
@@ -147,7 +154,7 @@ export const mockIssue = {
...
@@ -147,7 +154,7 @@ export const mockIssue = {
weight
:
null
,
weight
:
null
,
confidential
:
false
,
confidential
:
false
,
path
:
`/
${
mockIssueProjectPath
}
/-/issues/27`
,
path
:
`/
${
mockIssueProjectPath
}
/-/issues/27`
,
assignees
,
assignees
:
mockAssignees
,
labels
,
labels
,
epic
:
{
epic
:
{
id
:
'
gid://gitlab/Epic/41
'
,
id
:
'
gid://gitlab/Epic/41
'
,
...
@@ -165,7 +172,7 @@ export const mockIssue2 = {
...
@@ -165,7 +172,7 @@ export const mockIssue2 = {
weight
:
null
,
weight
:
null
,
confidential
:
false
,
confidential
:
false
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
assignees
,
assignees
:
mockAssignees
,
labels
,
labels
,
epic
:
{
epic
:
{
id
:
'
gid://gitlab/Epic/40
'
,
id
:
'
gid://gitlab/Epic/40
'
,
...
@@ -183,7 +190,7 @@ export const mockIssue3 = {
...
@@ -183,7 +190,7 @@ export const mockIssue3 = {
weight
:
null
,
weight
:
null
,
confidential
:
false
,
confidential
:
false
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
assignees
,
assignees
:
mockAssignees
,
labels
,
labels
,
epic
:
null
,
epic
:
null
,
};
};
...
@@ -198,7 +205,7 @@ export const mockIssue4 = {
...
@@ -198,7 +205,7 @@ export const mockIssue4 = {
weight
:
null
,
weight
:
null
,
confidential
:
false
,
confidential
:
false
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
path
:
'
/gitlab-org/gitlab-test/-/issues/28
'
,
assignees
,
assignees
:
mockAssignees
,
labels
,
labels
,
epic
:
null
,
epic
:
null
,
};
};
...
...
ee/spec/frontend/boards/stores/actions_spec.js
View file @
3a172309
...
@@ -19,9 +19,10 @@ import {
...
@@ -19,9 +19,10 @@ import {
mockIssue
,
mockIssue
,
mockIssue2
,
mockIssue2
,
mockEpic
,
mockEpic
,
mockEpics
,
rawIssue
,
rawIssue
,
mockMilestones
,
mockMilestones
,
mockAssignees
,
mockEpics
,
}
from
'
../mock_data
'
;
}
from
'
../mock_data
'
;
Vue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
...
@@ -1268,3 +1269,84 @@ describe('fetchMilestones', () => {
...
@@ -1268,3 +1269,84 @@ describe('fetchMilestones', () => {
});
});
});
});
});
});
describe
(
'
fetchAssignees
'
,
()
=>
{
const
queryResponse
=
{
data
:
{
workspace
:
{
assignees
:
{
nodes
:
mockAssignees
.
map
((
assignee
)
=>
({
user
:
assignee
})),
},
},
},
};
const
queryErrors
=
{
data
:
{
project
:
{
errors
:
[
'
You cannot view these assignees
'
],
assignees
:
{},
},
},
};
function
createStore
({
state
=
{
boardType
:
'
project
'
,
fullPath
:
'
gitlab-org/gitlab
'
,
assignees
:
[],
assigneesLoading
:
false
,
},
}
=
{})
{
return
new
Vuex
.
Store
({
state
,
mutations
,
});
}
it
(
'
throws error if state.boardType is not group or project
'
,
()
=>
{
const
store
=
createStore
({
state
:
{
boardType
:
'
invalid
'
,
},
});
expect
(()
=>
actions
.
fetchAssignees
(
store
)).
toThrow
(
new
Error
(
'
Unknown board type
'
));
});
it
(
'
sets assigneesLoading to true
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
store
=
createStore
();
actions
.
fetchAssignees
(
store
);
expect
(
store
.
state
.
assigneesLoading
).
toBe
(
true
);
});
describe
(
'
success
'
,
()
=>
{
it
(
'
sets state.assignees from query result
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
store
=
createStore
();
await
actions
.
fetchAssignees
(
store
);
expect
(
store
.
state
.
assigneesLoading
).
toBe
(
false
);
expect
(
store
.
state
.
assignees
).
toEqual
(
expect
.
objectContaining
(
mockAssignees
));
});
});
describe
(
'
failure
'
,
()
=>
{
it
(
'
throws an error and displays an error message
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryErrors
);
const
store
=
createStore
();
await
expect
(
actions
.
fetchAssignees
(
store
)).
rejects
.
toThrow
();
expect
(
store
.
state
.
assigneesLoading
).
toBe
(
false
);
expect
(
store
.
state
.
error
).
toBe
(
'
Failed to load assignees.
'
);
});
});
});
locale/gitlab.pot
View file @
3a172309
...
@@ -3224,6 +3224,9 @@ msgstr ""
...
@@ -3224,6 +3224,9 @@ msgstr ""
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgstr ""
msgstr ""
msgid "An assignee list displays issues assigned to the selected user"
msgstr ""
msgid "An email notification was recently sent from the admin panel. Please wait %{wait_time_in_words} before attempting to send another message."
msgid "An email notification was recently sent from the admin panel. Please wait %{wait_time_in_words} before attempting to send another message."
msgstr ""
msgstr ""
...
@@ -12629,6 +12632,9 @@ msgstr ""
...
@@ -12629,6 +12632,9 @@ msgstr ""
msgid "Failed to install."
msgid "Failed to install."
msgstr ""
msgstr ""
msgid "Failed to load assignees."
msgstr ""
msgid "Failed to load assignees. Please try again."
msgid "Failed to load assignees. Please try again."
msgstr ""
msgstr ""
...
@@ -26413,6 +26419,9 @@ msgstr ""
...
@@ -26413,6 +26419,9 @@ msgstr ""
msgid "Search an environment spec"
msgid "Search an environment spec"
msgstr ""
msgstr ""
msgid "Search assignees"
msgstr ""
msgid "Search authors"
msgid "Search authors"
msgstr ""
msgstr ""
...
...
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