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
fc2962ff
Commit
fc2962ff
authored
Nov 02, 2021
by
Florie Guibert
Committed by
Kushal Pandya
Nov 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor labels selector in board scope
parent
e94f48e8
Changes
31
Show whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
569 additions
and
221 deletions
+569
-221
app/assets/javascripts/boards/boards_util.js
app/assets/javascripts/boards/boards_util.js
+4
-0
app/assets/javascripts/boards/components/board_form.vue
app/assets/javascripts/boards/components/board_form.vue
+1
-38
app/assets/javascripts/boards/components/boards_selector.vue
app/assets/javascripts/boards/components/boards_selector.vue
+0
-26
app/assets/javascripts/boards/index.js
app/assets/javascripts/boards/index.js
+2
-0
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
...sets/javascripts/boards/mount_multiple_boards_switcher.js
+4
-4
app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql
...s/graphql_shared/queries/group_users_search.query.graphql
+1
-0
app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql
..._shared/queries/project_user_members_search.query.graphql
+1
-0
app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
...d/components/dropdown/dropdown_widget/dropdown_widget.vue
+56
-41
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
...ar/labels_select_widget/dropdown_contents_create_view.vue
+0
-5
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
...mponents/sidebar/labels_select_widget/dropdown_header.vue
+1
-1
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
...r/labels_select_widget/graphql/group_labels.query.graphql
+2
-1
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
...labels_select_widget/graphql/project_labels.query.graphql
+1
-0
app/views/shared/boards/_switcher.html.haml
app/views/shared/boards/_switcher.html.haml
+0
-4
ee/app/assets/javascripts/boards/components/assignee_select.vue
.../assets/javascripts/boards/components/assignee_select.vue
+0
-10
ee/app/assets/javascripts/boards/components/board_scope.vue
ee/app/assets/javascripts/boards/components/board_scope.vue
+7
-48
ee/app/assets/javascripts/boards/components/labels_select.vue
...pp/assets/javascripts/boards/components/labels_select.vue
+253
-0
ee/app/assets/javascripts/boards/components/milestone_select.vue
...assets/javascripts/boards/components/milestone_select.vue
+0
-10
ee/spec/features/boards/scoped_issue_board_spec.rb
ee/spec/features/boards/scoped_issue_board_spec.rb
+3
-3
ee/spec/features/epic_boards/epic_boards_spec.rb
ee/spec/features/epic_boards/epic_boards_spec.rb
+1
-1
ee/spec/features/labels_hierarchy_spec.rb
ee/spec/features/labels_hierarchy_spec.rb
+1
-1
ee/spec/frontend/boards/components/assignee_select_spec.js
ee/spec/frontend/boards/components/assignee_select_spec.js
+3
-0
ee/spec/frontend/boards/components/board_form_spec.js
ee/spec/frontend/boards/components/board_form_spec.js
+0
-3
ee/spec/frontend/boards/components/board_scope_spec.js
ee/spec/frontend/boards/components/board_scope_spec.js
+8
-10
ee/spec/frontend/boards/components/boards_selector_spec.js
ee/spec/frontend/boards/components/boards_selector_spec.js
+0
-4
ee/spec/frontend/boards/components/labels_select_spec.js
ee/spec/frontend/boards/components/labels_select_spec.js
+161
-0
locale/gitlab.pot
locale/gitlab.pot
+15
-0
spec/frontend/boards/components/board_form_spec.js
spec/frontend/boards/components/board_form_spec.js
+0
-3
spec/frontend/boards/components/boards_selector_spec.js
spec/frontend/boards/components/boards_selector_spec.js
+0
-4
spec/frontend/boards/mock_data.js
spec/frontend/boards/mock_data.js
+41
-0
spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
...nd/vue_shared/components/dropdown/dropdown_widget_spec.js
+2
-4
spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
...ared/components/sidebar/labels_select_widget/mock_data.js
+1
-0
No files found.
app/assets/javascripts/boards/boards_util.js
View file @
fc2962ff
import
{
sortBy
,
cloneDeep
}
from
'
lodash
'
;
import
{
isGid
}
from
'
~/graphql_shared/utils
'
;
import
{
ListType
,
MilestoneIDs
}
from
'
./constants
'
;
export
function
getMilestone
()
{
...
...
@@ -95,6 +96,9 @@ export function fullMilestoneId(id) {
}
export
function
fullLabelId
(
label
)
{
if
(
isGid
(
label
.
id
))
{
return
label
.
id
;
}
if
(
label
.
project_id
&&
label
.
project_id
!==
null
)
{
return
`gid://gitlab/ProjectLabel/
${
label
.
id
}
`
;
}
...
...
app/assets/javascripts/boards/components/board_form.vue
View file @
fc2962ff
...
...
@@ -57,39 +57,16 @@ export default {
type
:
Boolean
,
required
:
true
,
},
labelsPath
:
{
type
:
String
,
required
:
true
,
},
labelsWebUrl
:
{
type
:
String
,
required
:
true
,
},
scopedIssueBoardFeatureEnabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
projectId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
groupId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
weights
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
enableScopedLabels
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
currentBoard
:
{
type
:
Object
,
required
:
true
,
...
...
@@ -288,16 +265,7 @@ export default {
this
.
board
.
iteration_id
=
iterationId
;
},
setBoardLabels
(
labels
)
{
labels
.
forEach
((
label
)
=>
{
if
(
label
.
set
&&
!
this
.
board
.
labels
.
find
((
l
)
=>
l
.
id
===
label
.
id
))
{
this
.
board
.
labels
.
push
({
...
label
,
textColor
:
label
.
text_color
,
});
}
else
if
(
!
label
.
set
)
{
this
.
board
.
labels
=
this
.
board
.
labels
.
filter
((
selected
)
=>
selected
.
id
!==
label
.
id
);
}
});
this
.
board
.
labels
=
labels
;
},
setAssignee
(
assigneeId
)
{
this
.
$set
(
this
.
board
,
'
assignee
'
,
{
...
...
@@ -371,11 +339,6 @@ export default {
:collapse-scope=
"isNewForm"
:board=
"board"
:can-admin-board=
"canAdminBoard"
:labels-path=
"labelsPath"
:labels-web-url=
"labelsWebUrl"
:enable-scoped-labels=
"enableScopedLabels"
:project-id=
"projectId"
:group-id=
"groupId"
:weights=
"weights"
@
set-iteration=
"setIteration"
@
set-board-labels=
"setBoardLabels"
...
...
app/assets/javascripts/boards/components/boards_selector.vue
View file @
fc2962ff
...
...
@@ -64,22 +64,6 @@ export default {
type
:
Boolean
,
required
:
true
,
},
labelsPath
:
{
type
:
String
,
required
:
true
,
},
labelsWebUrl
:
{
type
:
String
,
required
:
true
,
},
projectId
:
{
type
:
Number
,
required
:
true
,
},
groupId
:
{
type
:
Number
,
required
:
true
,
},
scopedIssueBoardFeatureEnabled
:
{
type
:
Boolean
,
required
:
true
,
...
...
@@ -88,11 +72,6 @@ export default {
type
:
Array
,
required
:
true
,
},
enabledScopedLabels
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
...
...
@@ -354,14 +333,9 @@ export default {
<board-form
v-if=
"currentPage"
:labels-path=
"labelsPath"
:labels-web-url=
"labelsWebUrl"
:project-id=
"projectId"
:group-id=
"groupId"
:can-admin-board=
"canAdminBoard"
:scoped-issue-board-feature-enabled=
"scopedIssueBoardFeatureEnabled"
:weights=
"weights"
:enable-scoped-labels=
"enabledScopedLabels"
:current-board=
"currentBoard"
:current-page=
"currentPage"
@
cancel=
"cancel"
...
...
app/assets/javascripts/boards/index.js
View file @
fc2962ff
...
...
@@ -142,5 +142,7 @@ export default () => {
fullPath
:
$boardApp
.
dataset
.
fullPath
,
rootPath
:
$boardApp
.
dataset
.
boardsEndpoint
,
recentBoardsEndpoint
:
$boardApp
.
dataset
.
recentBoardsEndpoint
,
allowScopedLabels
:
$boardApp
.
dataset
.
scopedLabels
,
labelsManagePath
:
$boardApp
.
dataset
.
labelsManagePath
,
});
};
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
View file @
fc2962ff
...
...
@@ -13,6 +13,7 @@ const apolloProvider = new VueApollo({
export
default
(
params
=
{})
=>
{
const
boardsSwitcherElement
=
document
.
getElementById
(
'
js-multiple-boards-switcher
'
);
const
{
dataset
}
=
boardsSwitcherElement
;
return
new
Vue
({
el
:
boardsSwitcherElement
,
components
:
{
...
...
@@ -24,18 +25,17 @@ export default (params = {}) => {
fullPath
:
params
.
fullPath
,
rootPath
:
params
.
rootPath
,
recentBoardsEndpoint
:
params
.
recentBoardsEndpoint
,
allowScopedLabels
:
params
.
allowScopedLabels
,
labelsManagePath
:
params
.
labelsManagePath
,
allowLabelCreate
:
parseBoolean
(
dataset
.
canAdminBoard
),
},
data
()
{
const
{
dataset
}
=
boardsSwitcherElement
;
const
boardsSelectorProps
=
{
...
dataset
,
currentBoard
:
JSON
.
parse
(
dataset
.
currentBoard
),
hasMissingBoards
:
parseBoolean
(
dataset
.
hasMissingBoards
),
canAdminBoard
:
parseBoolean
(
dataset
.
canAdminBoard
),
multipleIssueBoardsAvailable
:
parseBoolean
(
dataset
.
multipleIssueBoardsAvailable
),
projectId
:
dataset
.
projectId
?
Number
(
dataset
.
projectId
)
:
0
,
groupId
:
Number
(
dataset
.
groupId
),
scopedIssueBoardFeatureEnabled
:
parseBoolean
(
dataset
.
scopedIssueBoardFeatureEnabled
),
weights
:
JSON
.
parse
(
dataset
.
weights
),
};
...
...
app/assets/javascripts/graphql_shared/queries/group_users_search.query.graphql
View file @
fc2962ff
...
...
@@ -3,6 +3,7 @@
query
usersSearch
(
$search
:
String
!,
$fullPath
:
ID
!)
{
workspace
:
group
(
fullPath
:
$fullPath
)
{
id
users
:
groupMembers
(
search
:
$search
,
relations
:
[
DIRECT
,
INHERITED
])
{
nodes
{
user
{
...
...
app/assets/javascripts/graphql_shared/queries/project_user_members_search.query.graphql
View file @
fc2962ff
query
searchProjectMembers
(
$fullPath
:
ID
!,
$search
:
String
)
{
project
(
fullPath
:
$fullPath
)
{
id
projectMembers
(
search
:
$search
)
{
nodes
{
user
{
...
...
app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
View file @
fc2962ff
...
...
@@ -45,7 +45,7 @@ export default {
default
:
false
,
},
selected
:
{
type
:
Object
,
type
:
[
Object
,
Array
]
,
required
:
false
,
default
:
()
=>
{},
},
...
...
@@ -54,6 +54,11 @@ export default {
required
:
false
,
default
:
''
,
},
allowMultiselect
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
isSearchEmpty
()
{
...
...
@@ -66,8 +71,14 @@ export default {
methods
:
{
selectOption
(
option
)
{
this
.
$emit
(
'
set-option
'
,
option
||
null
);
if
(
!
this
.
allowMultiselect
)
{
this
.
$refs
.
dropdown
.
hide
();
}
},
isSelected
(
option
)
{
if
(
Array
.
isArray
(
this
.
selected
))
{
return
this
.
selected
.
some
((
label
)
=>
label
.
title
===
option
.
title
);
}
return
(
this
.
selected
&&
((
option
.
name
&&
this
.
selected
.
name
===
option
.
name
)
||
...
...
@@ -78,7 +89,7 @@ export default {
this
.
$refs
.
dropdown
.
show
();
},
setFocus
()
{
this
.
$refs
.
search
.
focusInput
();
this
.
$refs
.
search
?
.
focusInput
();
},
setSearchTerm
(
search
)
{
this
.
$emit
(
'
set-search
'
,
search
);
...
...
@@ -108,6 +119,7 @@ export default {
@
shown=
"setFocus"
>
<template
#header
>
<slot
name=
"header"
>
<gl-search-box-by-type
ref=
"search"
:value=
"searchTerm"
...
...
@@ -115,7 +127,9 @@ export default {
class=
"js-dropdown-input-field"
@
input=
"setSearchTerm"
/>
</slot>
</
template
>
<slot
name=
"default"
>
<gl-dropdown-form
class=
"gl-relative gl-min-h-7"
>
<gl-loading-icon
v-if=
"isLoading"
...
...
@@ -130,7 +144,7 @@ export default {
:is-checked=
"isSelected(option)"
:is-check-centered=
"true"
:is-check-item=
"true"
@
click
=
"selectOption(option)"
@
click.native.capture.stop
=
"selectOption(option)"
>
<slot
name=
"preset-item"
:item=
"option"
>
{{
option
.
title
}}
...
...
@@ -147,7 +161,7 @@ export default {
:avatar-url=
"avatarUrl(option)"
:secondary-text=
"secondaryText(option)"
data-testid=
"unselected-option"
@
click
=
"selectOption(option)"
@
click.native.capture.stop
=
"selectOption(option)"
>
<slot
name=
"item"
:item=
"option"
>
{{ option.title }}
...
...
@@ -158,6 +172,7 @@ export default {
</gl-dropdown-item>
</template>
</gl-dropdown-form>
</slot>
<
template
#footer
>
<slot
name=
"footer"
></slot>
</
template
>
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
View file @
fc2962ff
...
...
@@ -32,11 +32,6 @@ export default {
type
:
String
,
required
:
true
,
},
issuableType
:
{
type
:
String
,
required
:
false
,
default
:
undefined
,
},
workspaceType
:
{
type
:
String
,
required
:
true
,
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
View file @
fc2962ff
...
...
@@ -39,7 +39,7 @@ export default {
},
methods
:
{
focusInput
()
{
this
.
$refs
.
searchInput
.
focusInput
();
this
.
$refs
.
searchInput
?
.
focusInput
();
},
},
};
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
View file @
fc2962ff
...
...
@@ -2,7 +2,8 @@
query
groupLabels
(
$fullPath
:
ID
!,
$searchTerm
:
String
)
{
workspace
:
group
(
fullPath
:
$fullPath
)
{
labels
(
searchTerm
:
$searchTerm
,
onlyGroupLabels
:
true
)
{
id
labels
(
searchTerm
:
$searchTerm
,
onlyGroupLabels
:
true
,
includeAncestorGroups
:
true
)
{
nodes
{
...
Label
}
...
...
app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
View file @
fc2962ff
...
...
@@ -2,6 +2,7 @@
query
projectLabels
(
$fullPath
:
ID
!,
$searchTerm
:
String
)
{
workspace
:
project
(
fullPath
:
$fullPath
)
{
id
labels
(
searchTerm
:
$searchTerm
,
includeAncestorGroups
:
true
)
{
nodes
{
...
Label
...
...
app/views/shared/boards/_switcher.html.haml
View file @
fc2962ff
...
...
@@ -9,9 +9,5 @@
has_missing_boards:
(
!
multiple_boards_available?
&&
current_board_parent
.
boards
.
size
>
1
).
to_s
,
can_admin_board:
can?
(
current_user
,
:admin_issue_board
,
parent
).
to_s
,
multiple_issue_boards_available:
parent
.
multiple_issue_boards_available?
.
to_s
,
labels_path:
labels_filter_path_with_defaults
(
only_group_labels:
true
,
include_descendant_groups:
true
),
labels_web_url:
parent
.
is_a?
(
Project
)
?
project_labels_path
(
@project
)
:
group_labels_path
(
@group
),
project_id:
@project
&
.
id
,
group_id:
@group
&
.
id
,
scoped_issue_board_feature_enabled:
Gitlab
.
ee?
&&
parent
.
feature_available?
(
:scoped_issue_board
)
?
'true'
:
'false'
,
weights:
weights
.
to_json
}
}
ee/app/assets/javascripts/boards/components/assignee_select.vue
View file @
fc2962ff
...
...
@@ -29,16 +29,6 @@ export default {
required
:
false
,
default
:
false
,
},
groupId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
projectId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
},
data
()
{
return
{
...
...
ee/app/assets/javascripts/boards/components/board_scope.vue
View file @
fc2962ff
<
script
>
import
{
mapGetters
}
from
'
vuex
'
;
import
{
__
}
from
'
~/locale
'
;
import
LabelsSelect
from
'
~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
'
;
import
AssigneeSelect
from
'
./assignee_select.vue
'
;
import
BoardScopeCurrentIteration
from
'
./board_scope_current_iteration.vue
'
;
import
BoardLabelsSelect
from
'
./labels_select.vue
'
;
import
BoardMilestoneSelect
from
'
./milestone_select.vue
'
;
import
BoardWeightSelect
from
'
./weight_select.vue
'
;
export
default
{
components
:
{
AssigneeSelect
,
LabelsSelect
,
Board
LabelsSelect
,
BoardMilestoneSelect
,
BoardScopeCurrentIteration
,
BoardWeightSelect
,
...
...
@@ -28,29 +28,6 @@ export default {
type
:
Object
,
required
:
true
,
},
labelsPath
:
{
type
:
String
,
required
:
true
,
},
labelsWebUrl
:
{
type
:
String
,
required
:
true
,
},
enableScopedLabels
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
projectId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
groupId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
weights
:
{
type
:
Array
,
required
:
false
,
...
...
@@ -103,8 +80,6 @@ export default {
<board-milestone-select
v-if=
"isIssueBoard"
:board=
"board"
:group-id=
"groupId"
:project-id=
"projectId"
:can-edit=
"canAdminBoard"
@
set-milestone=
"$emit('set-milestone', $event)"
/>
...
...
@@ -116,33 +91,17 @@ export default {
@
set-iteration=
"$emit('set-iteration', $event)"
/>
<labels-select
:allow-label-edit=
"canAdminBoard"
:allow-label-create=
"canAdminBoard"
:allow-label-remove=
"canAdminBoard"
:allow-multiselect=
"true"
:allow-scoped-labels=
"enableScopedLabels"
:selected-labels=
"board.labels"
:hide-collapsed-view=
"true"
:labels-fetch-path=
"labelsPath"
:labels-manage-path=
"labelsWebUrl"
:labels-filter-base-path=
"labelsWebUrl"
:labels-list-title=
"__('Select labels')"
:dropdown-button-text=
"__('Choose labels')"
variant=
"sidebar"
class=
"block labels"
<board-labels-select
:board=
"board"
:can-edit=
"canAdminBoard"
@
onLabelRemove=
"handleLabelRemove"
@
updateSelectedLabels=
"handleLabelClick"
>
{{
__
(
'
Any label
'
)
}}
</labels-select>
@
set-labels=
"handleLabelClick"
/>
<assignee-select
v-if=
"isIssueBoard"
:board=
"board"
:can-edit=
"canAdminBoard"
:project-id=
"projectId"
:group-id=
"groupId"
@
set-assignee=
"$emit('set-assignee', $event)"
/>
...
...
ee/app/assets/javascripts/boards/components/labels_select.vue
0 → 100644
View file @
fc2962ff
<
script
>
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
debounce
}
from
'
lodash
'
;
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
LabelItem
from
'
~/vue_shared/components/sidebar/labels_select_widget/label_item.vue
'
;
import
searchGroupLabels
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
'
;
import
searchProjectLabels
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
'
;
import
{
__
,
s__
,
sprintf
}
from
'
~/locale
'
;
import
DropdownValue
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
'
;
import
DropdownContentsCreateView
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
'
;
import
DropdownHeader
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_header.vue
'
;
import
DropdownFooter
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_footer.vue
'
;
import
DropdownWidget
from
'
~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
'
;
export
default
{
components
:
{
DropdownWidget
,
GlButton
,
LabelItem
,
DropdownValue
,
DropdownContentsCreateView
,
DropdownHeader
,
DropdownFooter
,
},
inject
:
[
'
fullPath
'
],
props
:
{
board
:
{
type
:
Object
,
required
:
true
,
},
canEdit
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
return
{
search
:
''
,
labels
:
[],
selected
:
this
.
board
.
labels
,
isEditing
:
false
,
showDropdownContentsCreateView
:
false
,
};
},
apollo
:
{
labels
:
{
query
()
{
return
this
.
isProjectBoard
?
searchProjectLabels
:
searchGroupLabels
;
},
variables
()
{
return
{
fullPath
:
this
.
fullPath
,
searchTerm
:
this
.
search
,
first
:
20
,
};
},
skip
()
{
return
!
this
.
isEditing
;
},
update
(
data
)
{
return
data
.
workspace
?.
labels
?.
nodes
.
map
((
label
)
=>
({
...
label
,
id
:
getIdFromGraphQLId
(
label
.
id
),
}));
},
error
()
{
this
.
setError
({
message
:
this
.
$options
.
i18n
.
errorSearchingLabels
});
},
},
},
computed
:
{
...
mapState
([
'
boardType
'
]),
...
mapGetters
([
'
isProjectBoard
'
]),
isLabelsEmpty
()
{
return
this
.
selected
.
length
===
0
;
},
selectedLabelsIds
()
{
return
this
.
selected
.
map
((
label
)
=>
label
.
id
);
},
isLoading
()
{
return
this
.
$apollo
.
queries
.
labels
.
loading
;
},
selectText
()
{
if
(
!
this
.
selected
.
length
)
{
return
this
.
$options
.
i18n
.
selectLabel
;
}
else
if
(
this
.
selected
.
length
>
1
)
{
return
sprintf
(
s__
(
'
LabelSelect|%{firstLabelName} +%{remainingLabelCount} more
'
),
{
firstLabelName
:
this
.
selected
[
0
].
title
,
remainingLabelCount
:
this
.
selected
.
length
-
1
,
});
}
return
this
.
selected
[
0
].
title
;
},
footerCreateLabelTitle
()
{
return
sprintf
(
__
(
'
Create %{workspace} label
'
),
{
workspace
:
this
.
boardType
,
});
},
footerManageLabelTitle
()
{
return
sprintf
(
__
(
'
Manage %{workspace} labels
'
),
{
workspace
:
this
.
boardType
,
});
},
labelType
()
{
return
this
.
boardType
;
},
},
methods
:
{
...
mapActions
([
'
setError
'
]),
isLabelSelected
(
label
)
{
return
this
.
selectedLabelsIds
.
includes
(
label
.
id
);
},
selectLabel
(
label
)
{
let
labels
=
[];
if
(
this
.
isLabelSelected
(
label
))
{
labels
=
this
.
selected
.
filter
(({
id
})
=>
id
!==
label
.
id
);
}
else
{
labels
=
[...
this
.
selected
,
label
];
}
this
.
selected
=
labels
;
this
.
$emit
(
'
set-labels
'
,
labels
);
},
onLabelRemove
(
labelId
)
{
const
labels
=
this
.
selected
.
filter
(({
id
})
=>
getIdFromGraphQLId
(
id
)
!==
labelId
);
this
.
selected
=
labels
;
this
.
$emit
(
'
set-labels
'
,
labels
);
},
toggleEdit
()
{
if
(
!
this
.
isEditing
)
{
this
.
showDropdown
();
}
else
{
this
.
hideDropdown
();
}
},
showDropdown
()
{
this
.
isEditing
=
true
;
this
.
$refs
.
editDropdown
.
showDropdown
();
debounce
(()
=>
{
this
.
setFocus
();
},
50
)();
},
hideDropdown
()
{
this
.
isEditing
=
false
;
},
setSearch
(
search
)
{
this
.
search
=
search
;
},
toggleDropdownContentsCreateView
()
{
this
.
showDropdownContentsCreateView
=
!
this
.
showDropdownContentsCreateView
;
},
toggleDropdownContent
()
{
this
.
toggleDropdownContentsCreateView
();
// Required to recalculate dropdown position as its size changes
if
(
this
.
$refs
.
editDropdown
?.
$refs
.
dropdown
?.
$refs
.
dropdown
)
{
this
.
$refs
.
editDropdown
.
$refs
.
dropdown
.
$refs
.
dropdown
.
$_popper
.
scheduleUpdate
();
}
},
setFocus
()
{
this
.
$refs
.
header
?.
focusInput
();
},
},
i18n
:
{
label
:
s__
(
'
BoardScope|Labels
'
),
anyLabel
:
s__
(
'
BoardScope|Any label
'
),
selectLabel
:
s__
(
'
BoardScope|Choose labels
'
),
dropdownTitleText
:
s__
(
'
BoardScope|Select labels
'
),
errorSearchingLabels
:
s__
(
'
BoardScope|An error occurred while searching for labels, please try again.
'
,
),
edit
:
s__
(
'
BoardScope|Edit
'
),
},
};
</
script
>
<
template
>
<div
class=
"block labels labels-select-wrapper"
>
<div
class=
"title gl-mb-3"
>
{{
$options
.
i18n
.
label
}}
<gl-button
v-if=
"canEdit"
category=
"tertiary"
size=
"small"
class=
"edit-link float-right"
@
click=
"toggleEdit"
>
{{
$options
.
i18n
.
edit
}}
</gl-button>
</div>
<div
class=
"gl-text-gray-500 gl-mb-2"
data-testid=
"selected-labels"
>
<div
v-if=
"isLabelsEmpty"
>
{{
$options
.
i18n
.
anyLabel
}}
</div>
<dropdown-value
v-else
:disable-labels=
"isLoading"
:selected-labels=
"selected"
:allow-label-remove=
"canEdit"
:labels-filter-base-path=
"''"
:labels-filter-param=
"'label_name'"
class=
"gl-mb-2"
@
onLabelRemove=
"onLabelRemove"
/>
</div>
<dropdown-widget
v-show=
"isEditing"
ref=
"editDropdown"
:select-text=
"selectText"
:options=
"labels"
:is-loading=
"isLoading"
:selected=
"selected"
:search-term=
"search"
:allow-multiselect=
"true"
data-testid=
"labels-select-contents-list"
@
hide=
"hideDropdown"
@
set-option=
"selectLabel"
@
set-search=
"setSearch"
>
<template
#header
>
<dropdown-header
ref=
"header"
v-model=
"search"
:labels-create-title=
"footerCreateLabelTitle"
:labels-list-title=
"$options.i18n.dropdownTitleText"
:show-dropdown-contents-create-view=
"showDropdownContentsCreateView"
@
toggleDropdownContentsCreateView=
"toggleDropdownContent"
@
closeDropdown=
"hideDropdown"
@
input=
"setSearch"
/>
</
template
>
<
template
#item=
"{ item }"
>
<label-item
:label=
"item"
/>
</
template
>
<
template
v-if=
"showDropdownContentsCreateView"
#default
>
<dropdown-contents-create-view
:full-path=
"fullPath"
:workspace-type=
"boardType"
:attr-workspace-path=
"fullPath"
:label-create-type=
"labelType"
@
hideCreateView=
"toggleDropdownContent"
/>
</
template
>
<
template
#footer
>
<dropdown-footer
v-if=
"!showDropdownContentsCreateView"
:footer-create-label-title=
"footerCreateLabelTitle"
:footer-manage-label-title=
"footerManageLabelTitle"
@
toggleDropdownContentsCreateView=
"toggleDropdownContent"
/>
</
template
>
</dropdown-widget>
</div>
</template>
ee/app/assets/javascripts/boards/components/milestone_select.vue
View file @
fc2962ff
...
...
@@ -23,16 +23,6 @@ export default {
type
:
Object
,
required
:
true
,
},
groupId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
projectId
:
{
type
:
Number
,
required
:
false
,
default
:
0
,
},
canEdit
:
{
type
:
Boolean
,
required
:
false
,
...
...
ee/spec/features/boards/scoped_issue_board_spec.rb
View file @
fc2962ff
...
...
@@ -116,7 +116,7 @@ RSpec.describe 'Scoped issue boards', :js do
page
.
within
(
'.labels'
)
do
click_button
'Edit'
page
.
within
(
'
.labels-select-contents-list
'
)
do
page
.
within
(
'
[data-testid="labels-select-contents-list"]
'
)
do
expect
(
page
).
to
have_content
(
group_label
.
title
)
expect
(
page
).
not_to
have_content
(
project_label
.
title
)
end
...
...
@@ -381,7 +381,7 @@ RSpec.describe 'Scoped issue boards', :js do
page
.
within
(
'.labels'
)
do
click_button
'Edit'
page
.
within
(
'
.labels-select-contents-list
'
)
do
page
.
within
(
'
[data-testid="labels-select-contents-list"]
'
)
do
expect
(
page
).
to
have_content
(
group_label
.
title
)
expect
(
page
).
not_to
have_content
(
project_label
.
title
)
end
...
...
@@ -581,7 +581,7 @@ RSpec.describe 'Scoped issue boards', :js do
click_button
'Edit'
if
value
.
is_a?
(
Array
)
value
.
each
{
|
value
|
click_
link
value
}
value
.
each
{
|
value
|
click_
on
value
}
elsif
filter
==
'weight'
page
.
within
(
".dropdown-menu"
)
do
click_button
value
...
...
ee/spec/features/epic_boards/epic_boards_spec.rb
View file @
fc2962ff
...
...
@@ -351,7 +351,7 @@ RSpec.describe 'epic boards', :js do
if
value
.
is_a?
(
Array
)
value
.
each
{
|
value
|
click_link
value
}
else
click_
link
value
click_
on
value
end
end
end
...
...
ee/spec/features/labels_hierarchy_spec.rb
View file @
fc2962ff
...
...
@@ -39,7 +39,7 @@ RSpec.describe 'Labels Hierarchy', :js do
wait_for_requests
click_
link
label
.
title
click_
on
label
.
title
end
click_button
'Save changes'
...
...
ee/spec/frontend/boards/components/assignee_select_spec.js
View file @
fc2962ff
...
...
@@ -35,6 +35,9 @@ describe('Assignee select component', () => {
const
createStore
=
({
isGroupBoard
=
false
,
isProjectBoard
=
false
}
=
{})
=>
{
store
=
new
Vuex
.
Store
({
...
defaultStore
,
actions
:
{
setError
:
jest
.
fn
(),
},
getters
:
{
isGroupBoard
:
()
=>
isGroupBoard
,
isProjectBoard
:
()
=>
isProjectBoard
,
...
...
ee/spec/frontend/boards/components/board_form_spec.js
View file @
fc2962ff
...
...
@@ -8,7 +8,6 @@ import createEpicBoardMutation from 'ee/boards/graphql/epic_board_create.mutatio
import
destroyEpicBoardMutation
from
'
ee/boards/graphql/epic_board_destroy.mutation.graphql
'
;
import
updateEpicBoardMutation
from
'
ee/boards/graphql/epic_board_update.mutation.graphql
'
;
import
{
TEST_HOST
}
from
'
helpers/test_constants
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
formType
}
from
'
~/boards/constants
'
;
...
...
@@ -37,8 +36,6 @@ const currentBoard = {
const
defaultProps
=
{
canAdminBoard
:
false
,
labelsPath
:
`
${
TEST_HOST
}
/labels/path`
,
labelsWebUrl
:
`
${
TEST_HOST
}
/-/labels`
,
currentBoard
,
currentPage
:
''
,
};
...
...
ee/spec/frontend/boards/components/board_scope_spec.js
View file @
fc2962ff
...
...
@@ -2,8 +2,9 @@ import { mount } from '@vue/test-utils';
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
BoardScope
from
'
ee/boards/components/board_scope.vue
'
;
import
{
TEST_HOST
}
from
'
helpers/test_constants
'
;
import
LabelsSelect
from
'
~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
'
;
import
BoardLabelsSelect
from
'
ee/boards/components/labels_select.vue
'
;
import
{
mockLabel1
}
from
'
jest/boards/mock_data
'
;
Vue
.
use
(
Vuex
);
...
...
@@ -26,17 +27,16 @@ describe('BoardScope', () => {
store
,
propsData
:
{
collapseScope
:
false
,
canAdminBoard
:
fals
e
,
canAdminBoard
:
tru
e
,
board
:
{
labels
:
[],
assignee
:
{},
},
labelsPath
:
`
${
TEST_HOST
}
/labels`
,
labelsWebUrl
:
`
${
TEST_HOST
}
/-/labels`
,
},
stubs
:
{
AssigneeSelect
:
true
,
BoardMilestoneSelect
:
true
,
BoardLabelsSelect
:
true
,
},
});
}
...
...
@@ -49,15 +49,13 @@ describe('BoardScope', () => {
wrapper
.
destroy
();
});
const
findLabelSelect
=
()
=>
wrapper
.
findComponent
(
LabelsSelect
);
const
findLabelSelect
=
()
=>
wrapper
.
findComponent
(
Board
LabelsSelect
);
describe
(
'
BoardScope
'
,
()
=>
{
it
(
'
emits selected labels to be added and removed from the board
'
,
async
()
=>
{
const
labels
=
[
{
id
:
'
1
'
,
set
:
true
,
color
:
'
#BADA55
'
,
text_color
:
'
#FFFFFF
'
}
];
const
labels
=
[
mockLabel1
];
expect
(
findLabelSelect
().
exists
()).
toBe
(
true
);
expect
(
findLabelSelect
().
text
()).
toContain
(
'
Any label
'
);
expect
(
findLabelSelect
().
props
(
'
selectedLabels
'
)).
toHaveLength
(
0
);
findLabelSelect
().
vm
.
$emit
(
'
updateSelectedLabels
'
,
labels
);
findLabelSelect
().
vm
.
$emit
(
'
set-labels
'
,
labels
);
await
nextTick
();
expect
(
wrapper
.
emitted
(
'
set-board-labels
'
)).
toEqual
([[
labels
]]);
});
...
...
ee/spec/frontend/boards/components/boards_selector_spec.js
View file @
fc2962ff
...
...
@@ -86,10 +86,6 @@ describe('BoardsSelector', () => {
hasMissingBoards
:
false
,
canAdminBoard
:
true
,
multipleIssueBoardsAvailable
:
true
,
labelsPath
:
`
${
TEST_HOST
}
/labels/path`
,
labelsWebUrl
:
`
${
TEST_HOST
}
/labels`
,
projectId
:
42
,
groupId
:
19
,
scopedIssueBoardFeatureEnabled
:
true
,
weights
:
[],
},
...
...
ee/spec/frontend/boards/components/labels_select_spec.js
0 → 100644
View file @
fc2962ff
import
{
GlButton
,
GlDropdown
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Vuex
from
'
vuex
'
;
import
LabelsSelect
from
'
ee/boards/components/labels_select.vue
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
boardObj
,
mockProjectLabelsResponse
,
mockGroupLabelsResponse
,
mockLabel1
,
}
from
'
jest/boards/mock_data
'
;
import
defaultStore
from
'
~/boards/stores
'
;
import
searchGroupLabels
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql
'
;
import
searchProjectLabels
from
'
~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql
'
;
import
DropdownValue
from
'
~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue
'
;
import
DropdownWidget
from
'
~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
describe
(
'
Labels select component
'
,
()
=>
{
let
wrapper
;
let
fakeApollo
;
let
store
;
const
selectedText
=
()
=>
wrapper
.
find
(
'
[data-testid="selected-labels"]
'
).
text
();
const
findEditButton
=
()
=>
wrapper
.
findComponent
(
GlButton
);
const
findDropdown
=
()
=>
wrapper
.
findComponent
(
DropdownWidget
);
const
findDropdownValue
=
()
=>
wrapper
.
findComponent
(
DropdownValue
);
const
projectLabelsQueryHandlerSuccess
=
jest
.
fn
().
mockResolvedValue
(
mockProjectLabelsResponse
);
const
groupLabelsQueryHandlerSuccess
=
jest
.
fn
().
mockResolvedValue
(
mockGroupLabelsResponse
);
async
function
openLabelsDropdown
()
{
findEditButton
().
vm
.
$emit
(
'
click
'
);
await
waitForPromises
();
}
const
createStore
=
({
isGroupBoard
=
false
,
isProjectBoard
=
false
}
=
{})
=>
{
store
=
new
Vuex
.
Store
({
...
defaultStore
,
actions
:
{
setError
:
jest
.
fn
(),
},
getters
:
{
isGroupBoard
:
()
=>
isGroupBoard
,
isProjectBoard
:
()
=>
isProjectBoard
,
},
state
:
{
boardType
:
isGroupBoard
?
'
group
'
:
'
project
'
,
},
});
};
const
createComponent
=
({
props
=
{}
}
=
{})
=>
{
fakeApollo
=
createMockApollo
([
[
searchProjectLabels
,
projectLabelsQueryHandlerSuccess
],
[
searchGroupLabels
,
groupLabelsQueryHandlerSuccess
],
]);
wrapper
=
shallowMount
(
LabelsSelect
,
{
localVue
,
store
,
apolloProvider
:
fakeApollo
,
propsData
:
{
board
:
boardObj
,
canEdit
:
true
,
...
props
,
},
provide
:
{
fullPath
:
'
gitlab-org
'
,
labelsManagePath
:
'
gitlab-org/labels
'
,
},
stubs
:
{
GlDropdown
,
GlDropdownItem
,
},
});
// We need to mock out `showDropdown` which
// invokes `show` method of BDropdown used inside GlDropdown.
wrapper
.
vm
.
$refs
.
editDropdown
.
showDropdown
=
jest
.
fn
();
};
beforeEach
(()
=>
{
createStore
({
isProjectBoard
:
true
});
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
fakeApollo
=
null
;
store
=
null
;
});
describe
(
'
when not editing
'
,
()
=>
{
it
(
'
defaults to Any label
'
,
()
=>
{
expect
(
selectedText
()).
toContain
(
'
Any label
'
);
});
it
(
'
skips the queries and does not render dropdown
'
,
()
=>
{
expect
(
projectLabelsQueryHandlerSuccess
).
not
.
toHaveBeenCalled
();
expect
(
findDropdown
().
isVisible
()).
toBe
(
false
);
});
it
(
'
renders selected labels in DropdownValue
'
,
async
()
=>
{
await
openLabelsDropdown
();
findDropdown
().
vm
.
$emit
(
'
set-option
'
,
mockLabel1
);
await
openLabelsDropdown
();
expect
(
findDropdownValue
().
isVisible
()).
toBe
(
true
);
expect
(
findDropdownValue
().
props
(
'
selectedLabels
'
)).
toEqual
([
mockLabel1
]);
});
});
describe
(
'
when editing
'
,
()
=>
{
it
(
'
trigger query and renders dropdown with passed labels
'
,
async
()
=>
{
await
openLabelsDropdown
();
expect
(
projectLabelsQueryHandlerSuccess
).
toHaveBeenCalled
();
expect
(
findDropdown
().
isVisible
()).
toBe
(
true
);
expect
(
findDropdown
().
props
(
'
options
'
)).
toHaveLength
(
2
);
});
});
describe
(
'
canEdit
'
,
()
=>
{
it
(
'
hides Edit button
'
,
async
()
=>
{
wrapper
.
setProps
({
canEdit
:
false
});
await
nextTick
();
expect
(
findEditButton
().
exists
()).
toBe
(
false
);
});
it
(
'
shows Edit button if true
'
,
()
=>
{
expect
(
findEditButton
().
exists
()).
toBe
(
true
);
});
});
it
.
each
`
boardType | mockedResponse | queryHandler | notCalledHandler
${
'
group
'
}
|
${
mockGroupLabelsResponse
}
|
${
groupLabelsQueryHandlerSuccess
}
|
${
projectLabelsQueryHandlerSuccess
}
${
'
project
'
}
|
${
mockProjectLabelsResponse
}
|
${
projectLabelsQueryHandlerSuccess
}
|
${
groupLabelsQueryHandlerSuccess
}
`
(
'
fetches $boardType labels
'
,
async
({
boardType
,
mockedResponse
,
queryHandler
,
notCalledHandler
})
=>
{
createStore
({
isProjectBoard
:
boardType
===
'
project
'
,
isGroupBoard
:
boardType
===
'
group
'
});
createComponent
({
[
queryHandler
]:
jest
.
fn
().
mockResolvedValue
(
mockedResponse
),
});
await
openLabelsDropdown
();
expect
(
queryHandler
).
toHaveBeenCalled
();
expect
(
notCalledHandler
).
not
.
toHaveBeenCalled
();
},
);
});
locale/gitlab.pot
View file @
fc2962ff
...
...
@@ -5491,6 +5491,9 @@ msgstr ""
msgid "BoardScope|An error occurred while getting milestones, please try again."
msgstr ""
msgid "BoardScope|An error occurred while searching for labels, please try again."
msgstr ""
msgid "BoardScope|An error occurred while searching for users, please try again."
msgstr ""
...
...
@@ -5500,12 +5503,21 @@ msgstr ""
msgid "BoardScope|Any assignee"
msgstr ""
msgid "BoardScope|Any label"
msgstr ""
msgid "BoardScope|Assignee"
msgstr ""
msgid "BoardScope|Choose labels"
msgstr ""
msgid "BoardScope|Edit"
msgstr ""
msgid "BoardScope|Labels"
msgstr ""
msgid "BoardScope|Milestone"
msgstr ""
...
...
@@ -5518,6 +5530,9 @@ msgstr ""
msgid "BoardScope|Select assignee"
msgstr ""
msgid "BoardScope|Select labels"
msgstr ""
msgid "BoardScope|Select milestone"
msgstr ""
...
...
spec/frontend/boards/components/board_form_spec.js
View file @
fc2962ff
import
{
GlModal
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
setWindowLocation
from
'
helpers/set_window_location_helper
'
;
import
{
TEST_HOST
}
from
'
helpers/test_constants
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
BoardForm
from
'
~/boards/components/board_form.vue
'
;
...
...
@@ -31,8 +30,6 @@ const currentBoard = {
const
defaultProps
=
{
canAdminBoard
:
false
,
labelsPath
:
`
${
TEST_HOST
}
/labels/path`
,
labelsWebUrl
:
`
${
TEST_HOST
}
/-/labels`
,
currentBoard
,
currentPage
:
''
,
};
...
...
spec/frontend/boards/components/boards_selector_spec.js
View file @
fc2962ff
...
...
@@ -78,10 +78,6 @@ describe('BoardsSelector', () => {
hasMissingBoards
:
false
,
canAdminBoard
:
true
,
multipleIssueBoardsAvailable
:
true
,
labelsPath
:
`
${
TEST_HOST
}
/labels/path`
,
labelsWebUrl
:
`
${
TEST_HOST
}
/labels`
,
projectId
:
42
,
groupId
:
19
,
scopedIssueBoardFeatureEnabled
:
true
,
weights
:
[],
},
...
...
spec/frontend/boards/mock_data.js
View file @
fc2962ff
...
...
@@ -12,6 +12,7 @@ export const boardObj = {
id
:
1
,
name
:
'
test
'
,
milestone_id
:
null
,
labels
:
[],
};
export
const
listObj
=
{
...
...
@@ -609,3 +610,43 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
unique
:
true
,
},
];
export
const
mockLabel1
=
{
id
:
'
gid://gitlab/GroupLabel/121
'
,
title
:
'
To Do
'
,
color
:
'
#F0AD4E
'
,
textColor
:
'
#FFFFFF
'
,
description
:
null
,
};
export
const
mockLabel2
=
{
id
:
'
gid://gitlab/GroupLabel/122
'
,
title
:
'
Doing
'
,
color
:
'
#F0AD4E
'
,
textColor
:
'
#FFFFFF
'
,
description
:
null
,
};
export
const
mockProjectLabelsResponse
=
{
data
:
{
workspace
:
{
id
:
'
gid://gitlab/Project/1
'
,
labels
:
{
nodes
:
[
mockLabel1
,
mockLabel2
],
},
},
__typename
:
'
Project
'
,
},
};
export
const
mockGroupLabelsResponse
=
{
data
:
{
workspace
:
{
id
:
'
gid://gitlab/Group/1
'
,
labels
:
{
nodes
:
[
mockLabel1
,
mockLabel2
],
},
},
__typename
:
'
Group
'
,
},
};
spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js
View file @
fc2962ff
...
...
@@ -34,6 +34,7 @@ describe('DropdownWidget component', () => {
// invokes `show` method of BDropdown used inside GlDropdown.
// Context: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54895#note_524281679
jest
.
spyOn
(
wrapper
.
vm
,
'
showDropdown
'
).
mockImplementation
();
jest
.
spyOn
(
findDropdown
().
vm
,
'
hide
'
).
mockImplementation
();
};
beforeEach
(()
=>
{
...
...
@@ -67,10 +68,7 @@ describe('DropdownWidget component', () => {
});
it
(
'
emits set-option event when clicking on an option
'
,
async
()
=>
{
wrapper
.
findAll
(
'
[data-testid="unselected-option"]
'
)
.
at
(
1
)
.
vm
.
$emit
(
'
click
'
,
new
Event
(
'
click
'
));
wrapper
.
findAll
(
'
[data-testid="unselected-option"]
'
).
at
(
1
).
trigger
(
'
click
'
);
await
wrapper
.
vm
.
$nextTick
();
expect
(
wrapper
.
emitted
(
'
set-option
'
)).
toEqual
([[
wrapper
.
props
().
options
[
1
]]]);
...
...
spec/frontend/vue_shared/components/sidebar/labels_select_widget/mock_data.js
View file @
fc2962ff
...
...
@@ -92,6 +92,7 @@ export const createLabelSuccessfulResponse = {
export
const
workspaceLabelsQueryResponse
=
{
data
:
{
workspace
:
{
id
:
'
gid://gitlab/Project/126
'
,
labels
:
{
nodes
:
[
{
...
...
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