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
cfccf903
Commit
cfccf903
authored
Aug 31, 2021
by
Florie Guibert
Committed by
Simon Knox
Aug 31, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up :graphql_board_list feature flag
Changelog: other
parent
8a7dbf13
Changes
46
Show whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
233 additions
and
1265 deletions
+233
-1265
app/assets/javascripts/boards/components/board_add_new_column.vue
...ts/javascripts/boards/components/board_add_new_column.vue
+3
-29
app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
...cripts/boards/components/board_card_layout_deprecated.vue
+1
-11
app/assets/javascripts/boards/components/board_content.vue
app/assets/javascripts/boards/components/board_content.vue
+5
-21
app/assets/javascripts/boards/components/board_settings_sidebar.vue
.../javascripts/boards/components/board_settings_sidebar.vue
+4
-15
app/assets/javascripts/boards/filtered_search_boards.js
app/assets/javascripts/boards/filtered_search_boards.js
+5
-10
app/assets/javascripts/boards/index.js
app/assets/javascripts/boards/index.js
+2
-27
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
...sets/javascripts/boards/mount_multiple_boards_switcher.js
+1
-14
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+4
-14
app/assets/javascripts/boards/stores/getters.js
app/assets/javascripts/boards/stores/getters.js
+0
-4
app/controllers/groups/boards_controller.rb
app/controllers/groups/boards_controller.rb
+0
-1
app/controllers/projects/boards_controller.rb
app/controllers/projects/boards_controller.rb
+0
-1
app/views/shared/boards/_show.html.haml
app/views/shared/boards/_show.html.haml
+0
-3
app/views/shared/boards/components/_sidebar.html.haml
app/views/shared/boards/components/_sidebar.html.haml
+0
-27
config/feature_flags/development/graphql_board_lists.yml
config/feature_flags/development/graphql_board_lists.yml
+0
-8
doc/user/project/issue_board.md
doc/user/project/issue_board.md
+1
-20
ee/app/assets/javascripts/boards/components/board_add_new_column.vue
...ts/javascripts/boards/components/board_add_new_column.vue
+8
-60
ee/app/assets/javascripts/boards/components/board_settings_wip_limit.vue
...avascripts/boards/components/board_settings_wip_limit.vue
+1
-14
ee/app/assets/javascripts/boards/components/boards_list_selector/index.js
...vascripts/boards/components/boards_list_selector/index.js
+1
-8
ee/app/assets/javascripts/boards/stores/actions.js
ee/app/assets/javascripts/boards/stores/actions.js
+24
-42
ee/app/assets/javascripts/boards/stores/boards_store_ee.js
ee/app/assets/javascripts/boards/stores/boards_store_ee.js
+0
-3
ee/app/assets/javascripts/boards/stores/getters.js
ee/app/assets/javascripts/boards/stores/getters.js
+0
-4
ee/spec/features/boards/group_boards/multiple_boards_spec.rb
ee/spec/features/boards/group_boards/multiple_boards_spec.rb
+0
-9
ee/spec/features/boards/group_boards/user_edits_issues_spec.rb
...ec/features/boards/group_boards/user_edits_issues_spec.rb
+0
-52
ee/spec/features/boards/sidebar_deprecated_spec.rb
ee/spec/features/boards/sidebar_deprecated_spec.rb
+0
-382
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
+2
-11
ee/spec/features/issues/filtered_search/filter_issues_by_iteration_spec.rb
...issues/filtered_search/filter_issues_by_iteration_spec.rb
+0
-8
ee/spec/frontend/boards/components/board_add_new_column_spec.js
...c/frontend/boards/components/board_add_new_column_spec.js
+0
-6
ee/spec/frontend/boards/components/board_content_spec.js
ee/spec/frontend/boards/components/board_content_spec.js
+12
-9
ee/spec/frontend/boards/components/board_list_selector/board_list_selector_spec.js
...omponents/board_list_selector/board_list_selector_spec.js
+1
-18
ee/spec/frontend/boards/components/board_settings_sidebar_spec.js
...frontend/boards/components/board_settings_sidebar_spec.js
+11
-40
ee/spec/frontend/boards/components/board_settings_wip_limit_spec.js
...ontend/boards/components/board_settings_wip_limit_spec.js
+50
-73
ee/spec/frontend/boards/stores/actions_spec.js
ee/spec/frontend/boards/stores/actions_spec.js
+6
-30
locale/gitlab.pot
locale/gitlab.pot
+0
-6
spec/features/boards/multi_select_spec.rb
spec/features/boards/multi_select_spec.rb
+2
-2
spec/features/boards/sidebar_labels_spec.rb
spec/features/boards/sidebar_labels_spec.rb
+2
-1
spec/features/boards/user_adds_lists_to_board_spec.rb
spec/features/boards/user_adds_lists_to_board_spec.rb
+3
-14
spec/features/groups/board_sidebar_spec.rb
spec/features/groups/board_sidebar_spec.rb
+0
-26
spec/features/labels_hierarchy_spec.rb
spec/features/labels_hierarchy_spec.rb
+0
-38
spec/frontend/boards/components/board_add_new_column_spec.js
spec/frontend/boards/components/board_add_new_column_spec.js
+0
-1
spec/frontend/boards/components/board_card_deprecated_spec.js
.../frontend/boards/components/board_card_deprecated_spec.js
+0
-38
spec/frontend/boards/components/board_card_layout_deprecated_spec.js
...nd/boards/components/board_card_layout_deprecated_spec.js
+2
-6
spec/frontend/boards/components/board_content_spec.js
spec/frontend/boards/components/board_content_spec.js
+14
-41
spec/frontend/boards/components/board_filtered_search_spec.js
.../frontend/boards/components/board_filtered_search_spec.js
+8
-14
spec/frontend/boards/components/board_settings_sidebar_spec.js
...frontend/boards/components/board_settings_sidebar_spec.js
+41
-93
spec/frontend/boards/mock_data.js
spec/frontend/boards/mock_data.js
+16
-0
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+3
-11
No files found.
app/assets/javascripts/boards/components/board_add_new_column.vue
View file @
cfccf903
...
...
@@ -2,9 +2,6 @@
import
{
GlFormRadio
,
GlFormRadioGroup
,
GlTooltipDirective
as
GlTooltip
}
from
'
@gitlab/ui
'
;
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
BoardAddNewColumnForm
from
'
~/boards/components/board_add_new_column_form.vue
'
;
import
{
ListType
}
from
'
~/boards/constants
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
export
default
{
components
:
{
...
...
@@ -24,7 +21,7 @@ export default {
},
computed
:
{
...
mapState
([
'
labels
'
,
'
labelsLoading
'
]),
...
mapGetters
([
'
getListByLabelId
'
,
'
shouldUseGraphQL
'
]),
...
mapGetters
([
'
getListByLabelId
'
]),
columnForSelected
()
{
return
this
.
getListByLabelId
(
this
.
selectedId
);
},
...
...
@@ -34,17 +31,6 @@ export default {
},
methods
:
{
...
mapActions
([
'
createList
'
,
'
fetchLabels
'
,
'
highlightList
'
,
'
setAddColumnFormVisibility
'
]),
highlight
(
listId
)
{
if
(
this
.
shouldUseGraphQL
)
{
this
.
highlightList
(
listId
);
}
else
{
const
list
=
boardsStore
.
state
.
lists
.
find
(({
id
})
=>
id
===
listId
);
list
.
highlighted
=
true
;
setTimeout
(()
=>
{
list
.
highlighted
=
false
;
},
2000
);
}
},
addList
()
{
if
(
!
this
.
selectedLabel
)
{
return
;
...
...
@@ -54,23 +40,11 @@ export default {
if
(
this
.
columnForSelected
)
{
const
listId
=
this
.
columnForSelected
.
id
;
this
.
highlight
(
listId
);
this
.
highlight
List
(
listId
);
return
;
}
if
(
this
.
shouldUseGraphQL
)
{
this
.
createList
({
labelId
:
this
.
selectedId
});
}
else
{
const
listObj
=
{
labelId
:
getIdFromGraphQLId
(
this
.
selectedId
),
title
:
this
.
selectedLabel
.
title
,
position
:
boardsStore
.
state
.
lists
.
length
-
2
,
list_type
:
ListType
.
label
,
label
:
this
.
selectedLabel
,
};
boardsStore
.
new
(
listObj
);
}
},
filterItems
(
searchTerm
)
{
...
...
app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
View file @
cfccf903
...
...
@@ -62,17 +62,7 @@ export default {
// Don't do anything if this happened on a no trigger element
if
(
e
.
target
.
classList
.
contains
(
'
js-no-trigger
'
))
return
;
if
(
this
.
glFeatures
.
graphqlBoardLists
||
this
.
isSwimlanesOn
)
{
this
.
setActiveId
({
id
:
this
.
issue
.
id
,
sidebarType
:
ISSUABLE
});
return
;
}
const
isMultiSelect
=
e
.
ctrlKey
||
e
.
metaKey
;
if
(
this
.
showDetail
||
isMultiSelect
)
{
this
.
showDetail
=
false
;
this
.
$emit
(
'
show
'
,
{
event
:
e
,
isMultiSelect
});
}
},
},
};
...
...
app/assets/javascripts/boards/components/board_content.vue
View file @
cfccf903
...
...
@@ -5,24 +5,20 @@ import Draggable from 'vuedraggable';
import
{
mapState
,
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
BoardAddNewColumn
from
'
ee_else_ce/boards/components/board_add_new_column.vue
'
;
import
defaultSortableConfig
from
'
~/sortable/sortable_config
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
DraggableItemTypes
}
from
'
../constants
'
;
import
BoardColumn
from
'
./board_column.vue
'
;
import
BoardColumnDeprecated
from
'
./board_column_deprecated.vue
'
;
export
default
{
draggableItemTypes
:
DraggableItemTypes
,
components
:
{
BoardAddNewColumn
,
BoardColumn
,
BoardColumnDeprecated
,
BoardContentSidebar
:
()
=>
import
(
'
~/boards/components/board_content_sidebar.vue
'
),
EpicBoardContentSidebar
:
()
=>
import
(
'
ee_component/boards/components/epic_board_content_sidebar.vue
'
),
EpicsSwimlanes
:
()
=>
import
(
'
ee_component/boards/components/epics_swimlanes.vue
'
),
GlAlert
,
},
mixins
:
[
glFeatureFlagMixin
()],
inject
:
[
'
canAdminList
'
],
props
:
{
lists
:
{
...
...
@@ -37,20 +33,15 @@ export default {
},
computed
:
{
...
mapState
([
'
boardLists
'
,
'
error
'
,
'
addColumnForm
'
]),
...
mapGetters
([
'
isSwimlanesOn
'
,
'
isEpicBoard
'
]),
useNewBoardColumnComponent
()
{
return
this
.
glFeatures
.
graphqlBoardLists
||
this
.
isSwimlanesOn
||
this
.
isEpicBoard
;
},
...
mapGetters
([
'
isSwimlanesOn
'
,
'
isEpicBoard
'
,
'
isIssueBoard
'
]),
addColumnFormVisible
()
{
return
this
.
addColumnForm
?.
visible
;
},
boardListsToUse
()
{
return
this
.
useNewBoardColumnComponent
?
sortBy
([...
Object
.
values
(
this
.
boardLists
)],
'
position
'
)
:
this
.
lists
;
return
sortBy
([...
Object
.
values
(
this
.
boardLists
)],
'
position
'
);
},
canDragColumns
()
{
return
(
this
.
isEpicBoard
||
this
.
glFeatures
.
graphqlBoardLists
)
&&
this
.
canAdminList
;
return
this
.
canAdminList
;
},
boardColumnWrapper
()
{
return
this
.
canDragColumns
?
Draggable
:
'
div
'
;
...
...
@@ -68,9 +59,6 @@ export default {
return
this
.
canDragColumns
?
options
:
{};
},
boardColumnComponent
()
{
return
this
.
useNewBoardColumnComponent
?
BoardColumn
:
BoardColumnDeprecated
;
},
},
methods
:
{
...
mapActions
([
'
moveList
'
,
'
unsetError
'
]),
...
...
@@ -95,8 +83,7 @@ export default {
class=
"boards-list gl-w-full gl-py-5 gl-px-3 gl-white-space-nowrap"
@
end=
"moveList"
>
<component
:is=
"boardColumnComponent"
<board-column
v-for=
"(list, index) in boardListsToUse"
:key=
"index"
ref=
"board"
...
...
@@ -118,10 +105,7 @@ export default {
:disabled=
"disabled"
/>
<board-content-sidebar
v-if=
"isSwimlanesOn || glFeatures.graphqlBoardLists"
data-testid=
"issue-boards-sidebar"
/>
<board-content-sidebar
v-if=
"isIssueBoard"
data-testid=
"issue-boards-sidebar"
/>
<epic-board-content-sidebar
v-else-if=
"isEpicBoard"
data-testid=
"epic-boards-sidebar"
/>
</div>
...
...
app/assets/javascripts/boards/components/board_settings_sidebar.vue
View file @
cfccf903
...
...
@@ -31,20 +31,13 @@ export default {
};
},
computed
:
{
...
mapGetters
([
'
isSidebarOpen
'
,
'
shouldUseGraphQL
'
,
'
isEpicBoard
'
]),
...
mapGetters
([
'
isSidebarOpen
'
,
'
isEpicBoard
'
]),
...
mapState
([
'
activeId
'
,
'
sidebarType
'
,
'
boardLists
'
]),
isWipLimitsOn
()
{
return
this
.
glFeatures
.
wipLimits
&&
!
this
.
isEpicBoard
;
},
activeList
()
{
/*
Warning: Though a computed property it is not reactive because we are
referencing a List Model class. Reactivity only applies to plain JS objects
*/
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
return
this
.
boardLists
[
this
.
activeId
];
}
return
boardsStore
.
state
.
lists
.
find
(({
id
})
=>
id
===
this
.
activeId
);
},
activeListLabel
()
{
return
this
.
activeList
.
label
;
...
...
@@ -73,12 +66,8 @@ export default {
deleteBoard
()
{
// eslint-disable-next-line no-alert
if
(
window
.
confirm
(
__
(
'
Are you sure you want to remove this list?
'
)))
{
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
this
.
track
(
'
click_button
'
,
{
label
:
'
remove_list
'
});
this
.
removeList
(
this
.
activeId
);
}
else
{
this
.
activeList
.
destroy
();
}
this
.
unsetActiveId
();
}
},
...
...
app/assets/javascripts/boards/filtered_search_boards.js
View file @
cfccf903
...
...
@@ -4,7 +4,6 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable
import
{
updateHistory
}
from
'
~/lib/utils/url_utility
'
;
import
FilteredSearchContainer
from
'
../filtered_search/container
'
;
import
vuexstore
from
'
./stores
'
;
import
boardsStore
from
'
./stores/boards_store
'
;
export
default
class
FilteredSearchBoards
extends
FilteredSearchManager
{
constructor
(
store
,
updateUrl
=
false
,
cantEdit
=
[])
{
...
...
@@ -26,7 +25,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
this
.
cantEdit
=
cantEdit
.
filter
((
i
)
=>
typeof
i
===
'
string
'
);
this
.
cantEditWithValue
=
cantEdit
.
filter
((
i
)
=>
typeof
i
===
'
object
'
);
if
(
vuexstore
.
getters
.
shouldUseGraphQL
&&
vuexstore
.
state
.
boardConfig
)
{
if
(
vuexstore
.
state
.
boardConfig
)
{
const
boardConfigPath
=
transformBoardConfig
(
vuexstore
.
state
.
boardConfig
);
// TODO Refactor: https://gitlab.com/gitlab-org/gitlab/-/issues/329274
// here we are using "window.location.search" as a temporary store
...
...
@@ -45,14 +44,10 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
const
groupByParam
=
new
URLSearchParams
(
window
.
location
.
search
).
get
(
'
group_by
'
);
this
.
store
.
path
=
`
${
path
.
substr
(
1
)}${
groupByParam
?
`&group_by=
${
groupByParam
}
`
:
''
}
`
;
if
(
vuexstore
.
getters
.
shouldUseGraphQL
)
{
updateHistory
({
url
:
`?
${
path
.
substr
(
1
)}${
groupByParam
?
`&group_by=
${
groupByParam
}
`
:
''
}
`
,
});
vuexstore
.
dispatch
(
'
performSearch
'
);
}
else
if
(
this
.
updateUrl
)
{
boardsStore
.
updateFiltersUrl
();
}
}
removeTokens
()
{
...
...
app/assets/javascripts/boards/index.js
View file @
cfccf903
...
...
@@ -2,7 +2,7 @@ import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import
PortalVue
from
'
portal-vue
'
;
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
{
mapActions
}
from
'
vuex
'
;
import
'
ee_else_ce/boards/models/issue
'
;
import
'
ee_else_ce/boards/models/list
'
;
...
...
@@ -78,10 +78,7 @@ export default () => {
initBoardsFilteredSearch
(
apolloProvider
);
}
if
(
!
gon
?.
features
?.
graphqlBoardLists
)
{
boardsStore
.
create
();
boardsStore
.
setTimeTrackingLimitToHours
(
$boardApp
.
dataset
.
timeTrackingLimitToHours
);
}
// eslint-disable-next-line @gitlab/no-runtime-template-compiler
issueBoardsApp
=
new
Vue
({
...
...
@@ -133,7 +130,6 @@ export default () => {
};
},
computed
:
{
...
mapGetters
([
'
shouldUseGraphQL
'
]),
detailIssueVisible
()
{
return
Object
.
keys
(
this
.
detailIssue
.
issue
).
length
;
},
...
...
@@ -174,14 +170,12 @@ export default () => {
eventHub
.
$on
(
'
newDetailIssue
'
,
this
.
updateDetailIssue
);
eventHub
.
$on
(
'
clearDetailIssue
'
,
this
.
clearDetailIssue
);
sidebarEventHub
.
$on
(
'
toggleSubscription
'
,
this
.
toggleSubscription
);
eventHub
.
$on
(
'
initialBoardLoad
'
,
this
.
initialBoardLoad
);
},
beforeDestroy
()
{
eventHub
.
$off
(
'
updateTokens
'
,
this
.
updateTokens
);
eventHub
.
$off
(
'
newDetailIssue
'
,
this
.
updateDetailIssue
);
eventHub
.
$off
(
'
clearDetailIssue
'
,
this
.
clearDetailIssue
);
sidebarEventHub
.
$off
(
'
toggleSubscription
'
,
this
.
toggleSubscription
);
eventHub
.
$off
(
'
initialBoardLoad
'
,
this
.
initialBoardLoad
);
},
mounted
()
{
if
(
!
gon
?.
features
?.
issueBoardsFilteredSearch
)
{
...
...
@@ -196,28 +190,9 @@ export default () => {
this
.
performSearch
();
boardsStore
.
disabled
=
this
.
disabled
;
if
(
!
this
.
shouldUseGraphQL
)
{
this
.
initialBoardLoad
();
}
},
methods
:
{
...
mapActions
([
'
setInitialBoardData
'
,
'
performSearch
'
,
'
setError
'
]),
initialBoardLoad
()
{
boardsStore
.
all
()
.
then
((
res
)
=>
res
.
data
)
.
then
((
lists
)
=>
{
lists
.
forEach
((
list
)
=>
boardsStore
.
addList
(
list
));
this
.
loading
=
false
;
})
.
catch
((
error
)
=>
{
this
.
setError
({
error
,
message
:
__
(
'
An error occurred while fetching the board lists. Please try again.
'
),
});
});
},
updateTokens
()
{
this
.
filterManager
.
updateTokens
();
},
...
...
app/assets/javascripts/boards/mount_multiple_boards_switcher.js
View file @
cfccf903
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
mapGetters
}
from
'
vuex
'
;
import
BoardsSelector
from
'
ee_else_ce/boards/components/boards_selector.vue
'
;
import
BoardsSelectorDeprecated
from
'
~/boards/components/boards_selector_deprecated.vue
'
;
import
store
from
'
~/boards/stores
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
Vue
.
use
(
VueApollo
);
...
...
@@ -25,9 +22,7 @@ export default (params = {}) => {
el
:
boardsSwitcherElement
,
components
:
{
BoardsSelector
,
BoardsSelectorDeprecated
,
},
mixins
:
[
glFeatureFlagMixin
()],
apolloProvider
,
store
,
provide
:
{
...
...
@@ -52,18 +47,10 @@ export default (params = {}) => {
return
{
boardsSelectorProps
};
},
computed
:
{
...
mapGetters
([
'
shouldUseGraphQL
'
,
'
isEpicBoard
'
]),
},
render
(
createElement
)
{
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
return
createElement
(
BoardsSelector
,
{
props
:
this
.
boardsSelectorProps
,
});
}
return
createElement
(
BoardsSelectorDeprecated
,
{
props
:
this
.
boardsSelectorProps
,
});
},
});
};
app/assets/javascripts/boards/stores/actions.js
View file @
cfccf903
...
...
@@ -82,11 +82,8 @@ export default {
'
setFilters
'
,
convertObjectPropsToCamelCase
(
queryToObject
(
window
.
location
.
search
,
{
gatherArrays
:
true
})),
);
if
(
gon
.
features
.
graphqlBoardLists
)
{
dispatch
(
'
fetchLists
'
);
dispatch
(
'
resetIssues
'
);
}
},
fetchLists
:
({
commit
,
state
,
dispatch
})
=>
{
...
...
@@ -182,7 +179,7 @@ export default {
});
},
fetchLabels
:
({
state
,
commit
,
getters
},
searchTerm
)
=>
{
fetchLabels
:
({
state
,
commit
},
searchTerm
)
=>
{
const
{
fullPath
,
boardType
}
=
state
;
const
variables
=
{
...
...
@@ -200,14 +197,7 @@ export default {
variables
,
})
.
then
(({
data
})
=>
{
let
labels
=
data
[
boardType
]?.
labels
.
nodes
;
if
(
!
getters
.
shouldUseGraphQL
&&
!
getters
.
isEpicBoard
)
{
labels
=
labels
.
map
((
label
)
=>
({
...
label
,
id
:
getIdFromGraphQLId
(
label
.
id
),
}));
}
const
labels
=
data
[
boardType
]?.
labels
.
nodes
;
commit
(
types
.
RECEIVE_LABELS_SUCCESS
,
labels
);
return
labels
;
...
...
app/assets/javascripts/boards/stores/getters.js
View file @
cfccf903
...
...
@@ -51,8 +51,4 @@ export default {
isEpicBoard
:
()
=>
{
return
false
;
},
shouldUseGraphQL
:
()
=>
{
return
gon
?.
features
?.
graphqlBoardLists
;
},
};
app/controllers/groups/boards_controller.rb
View file @
cfccf903
...
...
@@ -7,7 +7,6 @@ class Groups::BoardsController < Groups::ApplicationController
before_action
:assign_endpoint_vars
before_action
do
push_frontend_feature_flag
(
:graphql_board_lists
,
group
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:issue_boards_filtered_search
,
group
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:board_multi_select
,
group
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:swimlanes_buffered_rendering
,
group
,
default_enabled: :yaml
)
...
...
app/controllers/projects/boards_controller.rb
View file @
cfccf903
...
...
@@ -8,7 +8,6 @@ class Projects::BoardsController < Projects::ApplicationController
before_action
:assign_endpoint_vars
before_action
do
push_frontend_feature_flag
(
:swimlanes_buffered_rendering
,
project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:graphql_board_lists
,
project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:issue_boards_filtered_search
,
project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:board_multi_select
,
project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:iteration_cadences
,
project
&
.
group
,
default_enabled: :yaml
)
...
...
app/views/shared/boards/_show.html.haml
View file @
cfccf903
-
board
=
local_assigns
.
fetch
(
:board
,
nil
)
-
group
=
local_assigns
.
fetch
(
:group
,
false
)
-
@no_breadcrumb_container
=
true
-
@no_container
=
true
-
@content_wrapper_class
=
"
#{
@content_wrapper_class
}
gl-relative"
...
...
@@ -20,6 +19,4 @@
=
render
'shared/issuable/search_bar'
,
type: :boards
,
board:
board
#board-app
.boards-app.position-relative
{
"v-cloak"
=>
"true"
,
data:
board_data
,
":class"
=>
"{ 'is-compact': detailIssueVisible }"
}
%board-content
{
":lists"
=>
"state.lists"
,
":disabled"
=>
"disabled"
}
-
if
!
is_epic_board
&&
!
Feature
.
enabled?
(
:graphql_board_lists
,
default_enabled: :yaml
)
=
render
"shared/boards/components/sidebar"
,
group:
group
%board-settings-sidebar
app/views/shared/boards/components/_sidebar.html.haml
deleted
100644 → 0
View file @
8a7dbf13
%board-sidebar
{
"inline-template"
=>
true
,
":current-user"
=>
(
UserSerializer
.
new
.
represent
(
current_user
)
||
{}).
to_json
}
%transition
{
name:
"boards-sidebar-slide"
}
%aside
.right-sidebar.right-sidebar-expanded.boards-sidebar
{
"v-show"
=>
"showSidebar"
,
'aria-label'
:
s_
(
'Boards|Board'
),
'data-testid'
:
'issue-boards-sidebar'
}
.issuable-sidebar
.block.issuable-sidebar-header.position-relative
%span
.issuable-header-text.hide-collapsed.float-left
%strong
.bold
{{ issue.title }}
%br
/
%span
=
render_if_exists
"shared/boards/components/sidebar/issue_project_path"
=
precede
"#"
do
{{ issue.iid }}
%a
.gutter-toggle.position-absolute.position-top-0.position-right-0
{
role:
"button"
,
href:
"#"
,
"@click.prevent"
=>
"closeSidebar"
,
"aria-label"
=>
"Toggle sidebar"
}
=
custom_icon
(
"icon_close"
,
size:
15
)
.js-issuable-update
=
render
"shared/boards/components/sidebar/assignee"
=
render_if_exists
"shared/boards/components/sidebar/epic"
=
render
"shared/boards/components/sidebar/milestone"
=
render
"shared/boards/components/sidebar/time_tracker"
=
render
"shared/boards/components/sidebar/due_date"
=
render
"shared/boards/components/sidebar/labels"
=
render_if_exists
"shared/boards/components/sidebar/weight"
=
render
"shared/boards/components/sidebar/notifications"
config/feature_flags/development/graphql_board_lists.yml
deleted
100644 → 0
View file @
8a7dbf13
---
name
:
graphql_board_lists
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37905
rollout_issue_url
:
https://gitlab.com/gitlab-org/gitlab/-/issues/248908
milestone
:
'
13.4'
type
:
development
group
:
group::project management
default_enabled
:
true
doc/user/project/issue_board.md
View file @
cfccf903
...
...
@@ -229,8 +229,7 @@ and vice versa.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/285074) in GitLab 13.9.
> - [Deployed behind a feature flag](../feature_flags.md), enabled by default.
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/248908) in GitLab 14.1
> - Recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-graphql-based-issue-boards). **(FREE SELF)**
> - [Feature flag `graphql_board_lists`](https://gitlab.com/gitlab-org/gitlab/-/issues/248908) removed in GitLab 14.3
There can be
[
risks when disabling released features
](
../../administration/feature_flags.md#risks-when-disabling-released-features
)
.
...
...
@@ -673,24 +672,6 @@ A few things to remember:
by default. If you have more than 20 issues, start scrolling down and the next
20 appear.
### Enable or disable GraphQL-based issue boards **(FREE SELF)**
It is deployed behind a feature flag that is
**enabled by default**
as of GitLab 14.1.
[
GitLab administrators with access to the GitLab Rails console
](
../../administration/feature_flags.md
)
can disable it.
To enable it:
```
ruby
Feature
.
enable
(
:graphql_board_lists
)
```
To disable it:
```
ruby
Feature
.
disable
(
:graphql_board_lists
)
```
### Enable or disable iteration lists in boards **(PREMIUM SELF)**
The iteration list is under development but ready for production use. It is
...
...
ee/app/assets/javascripts/boards/components/board_add_new_column.vue
View file @
cfccf903
...
...
@@ -11,8 +11,6 @@ import {
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
BoardAddNewColumnForm
from
'
~/boards/components/board_add_new_column_form.vue
'
;
import
{
ListType
}
from
'
~/boards/constants
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
isScopedLabel
}
from
'
~/lib/utils/common_utils
'
;
import
{
__
}
from
'
~/locale
'
;
...
...
@@ -87,7 +85,7 @@ export default {
'
assignees
'
,
'
assigneesLoading
'
,
]),
...
mapGetters
([
'
getListByTypeId
'
,
'
shouldUseGraphQL
'
,
'
isEpicBoard
'
]),
...
mapGetters
([
'
getListByTypeId
'
,
'
isEpicBoard
'
]),
info
()
{
return
listTypeInfo
[
this
.
columnType
]
||
{};
...
...
@@ -132,16 +130,10 @@ export default {
return
false
;
}
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
const
key
=
`
${
this
.
columnType
}
Id`
;
return
this
.
getListByTypeId
({
[
key
]:
this
.
selectedId
,
});
}
return
boardsStore
.
state
.
lists
.
find
(
(
list
)
=>
list
[
this
.
columnType
]?.
id
===
getIdFromGraphQLId
(
this
.
selectedId
),
);
},
loading
()
{
...
...
@@ -187,17 +179,6 @@ export default {
'
fetchIterations
'
,
'
fetchMilestones
'
,
]),
highlight
(
listId
)
{
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
this
.
highlightList
(
listId
);
}
else
{
const
list
=
boardsStore
.
state
.
lists
.
find
(({
id
})
=>
id
===
listId
);
list
.
highlighted
=
true
;
setTimeout
(()
=>
{
list
.
highlighted
=
false
;
},
2000
);
}
},
addList
()
{
if
(
!
this
.
selectedItem
)
{
return
;
...
...
@@ -207,45 +188,12 @@ export default {
if
(
this
.
columnForSelected
)
{
const
listId
=
this
.
columnForSelected
.
id
;
this
.
highlight
(
listId
);
this
.
highlight
List
(
listId
);
return
;
}
if
(
this
.
shouldUseGraphQL
||
this
.
isEpicBoard
)
{
// eslint-disable-next-line @gitlab/require-i18n-strings
this
.
createList
({
[
`
${
this
.
columnType
}
Id`
]:
this
.
selectedId
});
}
else
{
const
{
length
}
=
boardsStore
.
state
.
lists
;
const
position
=
this
.
hideClosed
?
length
-
1
:
length
-
2
;
const
listObj
=
{
// eslint-disable-next-line @gitlab/require-i18n-strings
[
`
${
this
.
columnType
}
Id`
]:
getIdFromGraphQLId
(
this
.
selectedId
),
title
:
this
.
selectedItem
.
title
,
position
,
list_type
:
this
.
columnType
,
};
if
(
this
.
labelTypeSelected
)
{
listObj
.
label
=
this
.
selectedItem
;
}
else
if
(
this
.
milestoneTypeSelected
)
{
listObj
.
milestone
=
{
...
this
.
selectedItem
,
id
:
getIdFromGraphQLId
(
this
.
selectedItem
.
id
),
};
}
else
if
(
this
.
iterationTypeSelected
)
{
listObj
.
iteration
=
{
...
this
.
selectedItem
,
id
:
getIdFromGraphQLId
(
this
.
selectedItem
.
id
),
};
}
else
if
(
this
.
assigneeTypeSelected
)
{
listObj
.
assignee
=
{
...
this
.
selectedItem
,
id
:
getIdFromGraphQLId
(
this
.
selectedItem
.
id
),
};
}
boardsStore
.
new
(
listObj
);
}
},
filterItems
(
searchTerm
)
{
...
...
ee/app/assets/javascripts/boards/components/board_settings_wip_limit.vue
View file @
cfccf903
<
script
>
import
{
GlButton
,
GlFormInput
}
from
'
@gitlab/ui
'
;
import
{
mapActions
,
mapGetters
,
mapState
}
from
'
vuex
'
;
import
boardsStoreEE
from
'
ee/boards/stores/boards_store_ee
'
;
import
{
inactiveId
}
from
'
~/boards/constants
'
;
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
__
,
n__
}
from
'
~/locale
'
;
import
autofocusonshow
from
'
~/vue_shared/directives/autofocusonshow
'
;
...
...
@@ -36,7 +34,6 @@ export default {
},
computed
:
{
...
mapState
([
'
activeId
'
]),
...
mapGetters
([
'
shouldUseGraphQL
'
]),
wipLimitTypeText
()
{
return
n__
(
'
%d issue
'
,
'
%d issues
'
,
this
.
maxIssueCount
);
},
...
...
@@ -76,11 +73,6 @@ export default {
const
id
=
this
.
activeId
;
this
.
updateListWipLimit
({
maxIssueCount
:
wipLimit
,
listId
:
id
})
.
then
(()
=>
{
if
(
!
this
.
shouldUseGraphQL
)
{
boardsStoreEE
.
setMaxIssueCountOnList
(
id
,
wipLimit
);
}
})
.
catch
(()
=>
{
this
.
unsetActiveId
();
this
.
setError
({
...
...
@@ -96,11 +88,6 @@ export default {
},
clearWipLimit
()
{
this
.
updateListWipLimit
({
maxIssueCount
:
0
,
listId
:
this
.
activeId
})
.
then
(()
=>
{
if
(
!
this
.
shouldUseGraphQL
)
{
boardsStoreEE
.
setMaxIssueCountOnList
(
this
.
activeId
,
inactiveId
);
}
})
.
catch
(()
=>
{
this
.
unsetActiveId
();
this
.
setError
({
...
...
ee/app/assets/javascripts/boards/components/boards_list_selector/index.js
View file @
cfccf903
...
...
@@ -65,19 +65,12 @@ export default Vue.extend({
return
list
;
},
handleItemClick
(
item
)
{
if
(
this
.
vuexStore
.
getters
.
shouldUseGraphQL
&&
!
this
.
vuexStore
.
getters
.
getListByTitle
(
item
.
title
)
)
{
if
(
!
this
.
vuexStore
.
getters
.
getListByTitle
(
item
.
title
))
{
if
(
this
.
listType
===
'
milestones
'
)
{
this
.
vuexStore
.
dispatch
(
'
createList
'
,
{
milestoneId
:
fullMilestoneId
(
item
.
id
)
});
}
else
if
(
this
.
listType
===
'
assignees
'
)
{
this
.
vuexStore
.
dispatch
(
'
createList
'
,
{
assigneeId
:
fullUserId
(
item
.
id
)
});
}
}
else
if
(
!
this
.
store
.
findList
(
'
title
'
,
item
.
title
))
{
const
list
=
this
.
prepareListObject
(
item
);
this
.
store
.
new
(
list
);
}
},
},
...
...
ee/app/assets/javascripts/boards/stores/actions.js
View file @
cfccf903
...
...
@@ -6,15 +6,12 @@ import {
filterVariables
,
}
from
'
~/boards/boards_util
'
;
import
{
BoardType
}
from
'
~/boards/constants
'
;
import
eventHub
from
'
~/boards/eventhub
'
;
import
groupBoardMembersQuery
from
'
~/boards/graphql/group_board_members.query.graphql
'
;
import
listsIssuesQuery
from
'
~/boards/graphql/lists_issues.query.graphql
'
;
import
projectBoardMembersQuery
from
'
~/boards/graphql/project_board_members.query.graphql
'
;
import
actionsCE
,
{
gqlClient
}
from
'
~/boards/stores/actions
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
*
as
typesCE
from
'
~/boards/stores/mutation_types
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
historyPushState
,
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
mergeUrlParams
,
removeParams
,
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
...
...
@@ -39,7 +36,6 @@ import projectBoardIterationsQuery from '../graphql/project_board_iterations.que
import
updateBoardEpicUserPreferencesMutation
from
'
../graphql/update_board_epic_user_preferences.mutation.graphql
'
;
import
updateEpicLabelsMutation
from
'
../graphql/update_epic_labels.mutation.graphql
'
;
import
boardsStoreEE
from
'
./boards_store_ee
'
;
import
*
as
types
from
'
./mutation_types
'
;
const
fetchAndFormatListIssues
=
(
state
,
extraVariables
)
=>
{
...
...
@@ -121,13 +117,11 @@ export default {
if
(
getters
.
isSwimlanesOn
)
{
dispatch
(
'
resetEpics
'
);
dispatch
(
'
resetIssues
'
);
dispatch
(
'
fetchEpicsSwimlanes
'
);
dispatch
(
'
fetchLists
'
);
}
else
if
(
gon
.
features
.
graphqlBoardLists
||
getters
.
isEpicBoard
)
{
}
dispatch
(
'
fetchLists
'
);
dispatch
(
'
resetIssues
'
);
}
},
fetchEpicsSwimlanes
({
state
,
commit
},
{
fetchNext
=
false
}
=
{})
{
...
...
@@ -221,8 +215,7 @@ export default {
commit
(
types
.
SET_SHOW_LABELS
,
val
);
},
updateListWipLimit
({
commit
,
getters
,
dispatch
},
{
maxIssueCount
,
listId
})
{
if
(
getters
.
shouldUseGraphQL
)
{
updateListWipLimit
({
commit
,
dispatch
},
{
maxIssueCount
,
listId
})
{
return
gqlClient
.
mutate
({
mutation
:
listUpdateLimitMetricsMutation
,
...
...
@@ -246,13 +239,6 @@ export default {
.
catch
(()
=>
{
dispatch
(
'
handleUpdateListFailure
'
);
});
}
return
axios
.
put
(
`
${
boardsStoreEE
.
store
.
state
.
endpoints
.
listsEndpoint
}
/
${
listId
}
`
,
{
list
:
{
max_issue_count
:
maxIssueCount
,
},
});
},
fetchItemsForList
:
(
...
...
@@ -316,10 +302,6 @@ export default {
);
dispatch
(
'
fetchEpicsSwimlanes
'
);
dispatch
(
'
fetchLists
'
);
}
else
if
(
!
gon
.
features
.
graphqlBoardLists
)
{
historyPushState
(
removeParams
([
'
group_by
'
]),
window
.
location
.
href
,
true
);
boardsStore
.
create
();
eventHub
.
$emit
(
'
initialBoardLoad
'
);
}
else
{
historyPushState
(
removeParams
([
'
group_by
'
]),
window
.
location
.
href
,
true
);
}
...
...
ee/app/assets/javascripts/boards/stores/boards_store_ee.js
View file @
cfccf903
...
...
@@ -57,9 +57,6 @@ class BoardsStoreEE {
this
.
store
.
scopedLabels
=
{
enabled
:
parseBoolean
(
scopedLabels
),
};
if
(
!
gon
.
features
.
graphqlBoardLists
)
{
this
.
initBoardFilters
();
}
}
};
...
...
ee/app/assets/javascripts/boards/stores/getters.js
View file @
cfccf903
...
...
@@ -54,8 +54,4 @@ export default {
isEpicBoard
:
(
state
)
=>
{
return
state
.
issuableType
===
issuableTypes
.
epic
;
},
shouldUseGraphQL
:
(
state
)
=>
{
return
state
.
isShowingEpicsSwimlanes
||
gon
?.
features
?.
graphqlBoardLists
;
},
};
ee/spec/features/boards/group_boards/multiple_boards_spec.rb
View file @
cfccf903
...
...
@@ -61,13 +61,4 @@ RSpec.describe 'Multiple Issue Boards', :js do
it_behaves_like
'multiple issue boards'
end
context
'when graphql_board_lists FF disabled'
do
before
do
stub_feature_flags
(
graphql_board_lists:
false
)
stub_licensed_features
(
multiple_group_issue_boards:
true
)
end
it_behaves_like
'multiple issue boards'
end
end
ee/spec/features/boards/group_boards/user_edits_issues_spec.rb
deleted
100644 → 0
View file @
8a7dbf13
# frozen_string_literal: true
# To be removed as :graphql_board_lists gets removed
# https://gitlab.com/gitlab-org/gitlab/-/issues/248908
require
'spec_helper'
RSpec
.
describe
'label issues'
,
:js
do
include
BoardHelpers
let
(
:user
)
{
create
(
:user
)
}
let
(
:group
)
{
create
(
:group
,
:public
)
}
let
(
:project
)
{
create
(
:project
,
:public
,
namespace:
group
)
}
let
(
:board
)
{
create
(
:board
,
group:
group
)
}
let!
(
:development
)
{
create
(
:label
,
project:
project
,
name:
'Development'
)
}
let!
(
:issue
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
development
])
}
let!
(
:list
)
{
create
(
:list
,
board:
board
,
label:
development
,
position:
0
)
}
before
do
stub_licensed_features
(
multiple_group_issue_boards:
true
)
# stubbing until sidebar work is done: https://gitlab.com/gitlab-org/gitlab/-/issues/230711
stub_feature_flags
(
graphql_board_lists:
false
)
group
.
add_maintainer
(
user
)
sign_in
(
user
)
visit
group_boards_path
(
group
)
wait_for_requests
end
it
'adds a new group label from sidebar'
do
card
=
find
(
'.board:nth-child(2)'
).
first
(
'.board-card'
)
click_card
(
card
)
page
.
within
'.right-sidebar .labels'
do
click_link
'Edit'
click_link
'Create group label'
fill_in
'new_label_name'
,
with:
'test label'
first
(
'.suggest-colors-dropdown a'
).
click
# We need to hover before clicking to trigger
# dropdown repositioning so that the click isn't flaky
create_button
=
find_button
(
'Create'
)
create_button
.
hover
create_button
.
click
end
page
.
within
'.labels'
do
expect
(
page
).
to
have_link
'test label'
end
end
end
ee/spec/features/boards/sidebar_deprecated_spec.rb
deleted
100644 → 0
View file @
8a7dbf13
# frozen_string_literal: true
# To be removed as :graphql_board_lists gets removed
# https://gitlab.com/gitlab-org/gitlab/-/issues/248908
require
'spec_helper'
RSpec
.
describe
'Issue Boards'
,
:js
do
include
BoardHelpers
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:user2
)
{
create
(
:user
)
}
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
group:
group
)
}
let_it_be
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let_it_be
(
:development
)
{
create
(
:label
,
project:
project
,
name:
'Development'
)
}
let_it_be
(
:stretch
)
{
create
(
:label
,
project:
project
,
name:
'Stretch'
)
}
let_it_be
(
:issue1
)
{
create
(
:labeled_issue
,
project:
project
,
assignees:
[
user
],
milestone:
milestone
,
labels:
[
development
],
weight:
3
,
relative_position:
2
)
}
let_it_be
(
:issue2
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
development
,
stretch
],
relative_position:
1
)
}
let_it_be
(
:board
)
{
create
(
:board
,
project:
project
)
}
let_it_be
(
:list
)
{
create
(
:list
,
board:
board
,
label:
development
,
position:
0
)
}
let_it_be
(
:scoped_label_1
)
{
create
(
:label
,
project:
project
,
name:
'Scoped1::Label1'
)
}
let_it_be
(
:scoped_label_2
)
{
create
(
:label
,
project:
project
,
name:
'Scoped2::Label2'
)
}
let
(
:card1
)
{
find
(
'.board:nth-child(2)'
).
find
(
'.board-card:nth-child(2)'
)
}
let
(
:card2
)
{
find
(
'.board:nth-child(2)'
).
find
(
'.board-card:nth-child(1)'
)
}
before
do
stub_feature_flags
(
graphql_board_lists:
false
)
stub_licensed_features
(
multiple_issue_assignees:
true
)
project
.
add_maintainer
(
user
)
project
.
team
.
add_developer
(
user2
)
sign_in
user
visit
project_board_path
(
project
,
board
)
wait_for_requests
end
context
'assignee'
,
quarantine:
'https://gitlab.com/gitlab-org/gitlab/-/issues/332078'
do
it
'updates the issues assignee'
do
click_card
(
card2
)
page
.
within
(
'.assignee'
)
do
click_button
(
'Edit'
)
wait_for_requests
assignee
=
first
(
'.gl-avatar-labeled'
).
find
(
'.gl-avatar-labeled-label'
).
text
page
.
within
(
'.dropdown-menu-user'
)
do
first
(
'.gl-avatar-labeled'
).
click
end
click_button
(
'Apply'
)
wait_for_requests
expect
(
page
).
to
have_content
(
assignee
)
end
expect
(
card2
).
to
have_selector
(
'.avatar'
)
end
it
'adds multiple assignees'
do
click_card
(
card1
)
page
.
within
(
'.assignee'
)
do
click_button
(
'Edit'
)
wait_for_requests
assignee
=
all
(
'.gl-avatar-labeled'
)[
1
].
find
(
'.gl-avatar-labeled-label'
).
text
page
.
within
(
'.dropdown-menu-user'
)
do
find
(
'[data-testid="unassign"]'
).
click
all
(
'.gl-avatar-labeled'
)[
0
].
click
all
(
'.gl-avatar-labeled'
)[
1
].
click
end
click_button
(
'Apply'
)
wait_for_requests
aggregate_failures
do
expect
(
page
).
to
have_link
(
nil
,
title:
user
.
name
)
expect
(
page
).
to
have_link
(
nil
,
title:
assignee
)
end
end
expect
(
card1
.
all
(
'.avatar'
).
length
).
to
eq
(
2
)
end
it
'removes the assignee'
do
click_card
(
card1
)
page
.
within
(
'.assignee'
)
do
click_button
(
'Edit'
)
page
.
within
(
'.dropdown-menu-user'
)
do
find
(
'[data-testid="unassign"]'
).
click
end
click_button
(
'Apply'
)
expect
(
page
).
to
have_content
(
'None'
)
end
expect
(
card1
).
not_to
have_selector
(
'.avatar'
)
end
it
'assignees to current user'
do
click_card
(
card2
)
page
.
within
(
'.assignee'
)
do
expect
(
page
).
to
have_content
(
'None'
)
click_button
'assign yourself'
wait_for_requests
expect
(
page
).
to
have_content
(
user
.
name
)
end
expect
(
card2
).
to
have_selector
(
'.avatar'
)
end
it
'updates assignee dropdown'
do
click_card
(
card2
)
page
.
within
(
'.assignee'
)
do
click_button
(
'Edit'
)
wait_for_requests
assignee
=
first
(
'.gl-avatar-labeled'
).
find
(
'.gl-avatar-labeled-label'
).
text
page
.
within
(
'.dropdown-menu-user'
)
do
first
(
'.gl-avatar-labeled'
).
click
end
click_button
(
'Apply'
)
wait_for_requests
expect
(
page
).
to
have_content
(
assignee
)
end
click_card
(
card1
)
page
.
within
(
'.assignee'
)
do
click_button
(
'Edit'
)
expect
(
find
(
'.dropdown-menu'
)).
to
have_selector
(
'.gl-new-dropdown-item-check-icon'
)
end
end
end
context
'epic'
do
before
do
stub_licensed_features
(
epics:
true
)
group
.
add_owner
(
user
)
visit
project_board_path
(
project
,
board
)
wait_for_requests
end
context
'when the issue is not associated with an epic'
do
it
'displays `None` for value of epic'
do
click_card
(
card1
)
expect
(
find
(
'.js-epic-label'
).
text
).
to
have_content
(
'None'
)
end
end
context
'when the issue is associated with an epic'
do
let
(
:epic1
)
{
create
(
:epic
,
group:
group
,
title:
'Foo'
)
}
let!
(
:epic2
)
{
create
(
:epic
,
group:
group
,
title:
'Bar'
)
}
let!
(
:epic_issue
)
{
create
(
:epic_issue
,
issue:
issue1
,
epic:
epic1
)
}
it
'displays name of epic and links to it'
do
click_card
(
card1
)
expect
(
find
(
'.js-epic-label'
)).
to
have_link
(
epic1
.
title
,
href:
epic_path
(
epic1
))
end
it
'updates the epic associated with the issue'
do
click_card
(
card1
)
page
.
within
(
'.js-epic-block'
)
do
page
.
find
(
'.sidebar-dropdown-toggle'
).
click
wait_for_requests
find
(
'.gl-new-dropdown-item'
,
text:
epic2
.
title
).
click
wait_for_requests
expect
(
page
.
find
(
'.value'
)).
to
have_content
(
epic2
.
title
)
end
# Ensure that boards_store is also updated the epic associated with the issue.
click_card
(
card1
)
click_card
(
card1
)
expect
(
find
(
'.js-epic-label'
)).
to
have_content
(
epic2
.
title
)
end
end
end
context
'weight'
do
it
'displays weight async'
do
click_card
(
card1
)
expect
(
find
(
'.js-weight-weight-label'
).
text
).
to
have_content
(
issue1
.
weight
)
end
it
'updates weight in sidebar to 1'
do
click_card
(
card1
)
page
.
within
'.weight'
do
click_link
'Edit'
find
(
'.block.weight input'
).
send_keys
1
,
:enter
page
.
within
'.value'
do
expect
(
page
).
to
have_content
'1'
end
end
# Ensure the request was sent and things are persisted
visit
project_board_path
(
project
,
board
)
wait_for_requests
click_card
(
card1
)
page
.
within
'.weight .value'
do
expect
(
page
).
to
have_content
'1'
end
end
it
'updates weight in sidebar to no weight'
do
click_card
(
card1
)
page
.
within
'.weight'
do
click_link
'remove weight'
page
.
within
'.value'
do
expect
(
page
).
to
have_content
'None'
end
end
# Ensure the request was sent and things are persisted
visit
project_board_path
(
project
,
board
)
wait_for_requests
click_card
(
card1
)
page
.
within
'.weight .value'
do
expect
(
page
).
to
have_content
'None'
end
end
context
'unlicensed'
do
before
do
stub_licensed_features
(
issue_weights:
false
)
visit
project_board_path
(
project
,
board
)
wait_for_requests
end
it
'hides weight'
do
click_card
(
card1
)
expect
(
page
).
not_to
have_selector
(
'.js-weight-weight-label'
)
end
end
end
context
'scoped labels'
do
before
do
stub_licensed_features
(
scoped_labels:
true
)
visit
project_board_path
(
project
,
board
)
wait_for_requests
end
it
'adds multiple scoped labels'
do
click_card
(
card1
)
page
.
within
(
'.labels'
)
do
click_link
'Edit'
wait_for_requests
click_link
scoped_label_1
.
title
wait_for_requests
click_link
scoped_label_2
.
title
wait_for_requests
find
(
'.dropdown-menu-close-icon'
).
click
page
.
within
(
'.value'
)
do
aggregate_failures
do
expect
(
page
).
to
have_selector
(
'.gl-label-scoped'
,
count:
2
)
expect
(
page
).
to
have_content
(
scoped_label_1
.
scoped_label_key
)
expect
(
page
).
to
have_content
(
scoped_label_1
.
scoped_label_value
)
expect
(
page
).
to
have_content
(
scoped_label_2
.
scoped_label_key
)
expect
(
page
).
to
have_content
(
scoped_label_2
.
scoped_label_value
)
end
end
end
end
context
'with scoped label assigned'
do
let!
(
:issue3
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
development
,
scoped_label_1
,
scoped_label_2
],
relative_position:
3
)
}
let
(
:card3
)
{
find
(
'.board:nth-child(2)'
).
find
(
'.board-card:nth-child(1)'
)
}
before
do
stub_licensed_features
(
scoped_labels:
true
)
visit
project_board_path
(
project
,
board
)
wait_for_requests
end
it
'removes existing scoped label'
do
click_card
(
card3
)
page
.
within
(
'.labels'
)
do
click_link
'Edit'
wait_for_requests
click_link
scoped_label_2
.
title
wait_for_requests
find
(
'.dropdown-menu-close-icon'
).
click
page
.
within
(
'.value'
)
do
aggregate_failures
do
expect
(
page
).
to
have_selector
(
'.gl-label-scoped'
,
count:
1
)
expect
(
page
).
not_to
have_content
(
scoped_label_1
.
scoped_label_value
)
expect
(
page
).
to
have_content
(
scoped_label_2
.
scoped_label_key
)
expect
(
page
).
to
have_content
(
scoped_label_2
.
scoped_label_value
)
end
end
end
aggregate_failures
do
expect
(
card3
).
to
have_selector
(
'.gl-label-scoped'
,
count:
1
)
expect
(
card3
).
not_to
have_content
(
scoped_label_1
.
scoped_label_key
)
expect
(
card3
).
not_to
have_content
(
scoped_label_1
.
scoped_label_value
)
expect
(
card3
).
to
have_content
(
scoped_label_2
.
scoped_label_key
)
expect
(
card3
).
to
have_content
(
scoped_label_2
.
scoped_label_value
)
end
end
end
end
context
'when opening sidebars'
do
let
(
:settings_button
)
{
find
(
'.js-board-settings-button'
)
}
it
'closes card sidebar when opening settings sidebar'
do
click_card
(
card1
)
expect
(
page
).
to
have_selector
(
'.right-sidebar'
)
settings_button
.
click
expect
(
page
).
to
have_selector
(
'.js-board-settings-sidebar'
)
expect
(
page
).
not_to
have_selector
(
'.right-sidebar'
)
end
it
'closes settings sidebar when opening card sidebar'
do
settings_button
.
click
expect
(
page
).
to
have_selector
(
'.js-board-settings-sidebar'
)
click_card
(
card1
)
expect
(
page
).
to
have_selector
(
'.right-sidebar'
)
expect
(
page
).
not_to
have_selector
(
'.js-board-settings-sidebar'
)
end
end
end
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
View file @
cfccf903
...
...
@@ -3,8 +3,6 @@
require
'spec_helper'
RSpec
.
describe
'User adds milestone lists'
,
:js
do
using
RSpec
::
Parameterized
::
TableSyntax
let_it_be
(
:group
)
{
create
(
:group
,
:nested
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
namespace:
group
)
}
let_it_be
(
:group_board
)
{
create
(
:board
,
group:
group
)
}
...
...
@@ -25,11 +23,8 @@ RSpec.describe 'User adds milestone lists', :js do
group
.
add_owner
(
user
)
end
where
(
:board_type
,
:graphql_board_lists_enabled
)
do
:project
|
true
:project
|
false
:group
|
true
:group
|
false
where
(
:board_type
)
do
[[
:project
],
[
:group
]]
end
with_them
do
...
...
@@ -43,10 +38,6 @@ RSpec.describe 'User adds milestone lists', :js do
set_cookie
(
'sidebar_collapsed'
,
'true'
)
stub_feature_flags
(
graphql_board_lists:
graphql_board_lists_enabled
)
if
board_type
==
:project
visit
project_board_path
(
project
,
project_board
)
elsif
board_type
==
:group
...
...
ee/spec/features/issues/filtered_search/filter_issues_by_iteration_spec.rb
View file @
cfccf903
...
...
@@ -145,14 +145,6 @@ RSpec.describe 'Filter issues by iteration', :js do
let
(
:issue_title_selector
)
{
'.board-card .board-card-title'
}
it_behaves_like
'filters by iteration'
context
'when graphql_board_lists is disabled'
do
before
do
stub_feature_flags
(
graphql_board_lists:
false
)
end
it_behaves_like
'filters by iteration'
end
end
context
'group board'
do
...
...
ee/spec/frontend/boards/components/board_add_new_column_spec.js
View file @
cfccf903
...
...
@@ -15,7 +15,6 @@ Vue.use(Vuex);
describe
(
'
BoardAddNewColumn
'
,
()
=>
{
let
wrapper
;
let
shouldUseGraphQL
;
const
selectItem
=
(
id
)
=>
{
wrapper
.
findByTestId
(
'
selectItem
'
).
vm
.
$emit
(
'
change
'
,
id
);
...
...
@@ -59,7 +58,6 @@ describe('BoardAddNewColumn', () => {
...
actions
,
},
getters
:
{
shouldUseGraphQL
:
()
=>
shouldUseGraphQL
,
getListByTypeId
:
()
=>
getListByTypeId
,
isEpicBoard
:
()
=>
false
,
},
...
...
@@ -103,10 +101,6 @@ describe('BoardAddNewColumn', () => {
radio
.
vm
.
$emit
(
'
change
'
,
type
);
};
beforeEach
(()
=>
{
shouldUseGraphQL
=
true
;
});
it
(
'
clicking cancel hides the form
'
,
()
=>
{
const
setAddColumnFormVisibility
=
jest
.
fn
();
mountComponent
({
...
...
ee/spec/frontend/boards/components/board_content_spec.js
View file @
cfccf903
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
EpicBoardContentSidebar
from
'
ee/boards/components/epic_board_content_sidebar.vue
'
;
import
BoardContent
from
'
~/boards/components/board_content.vue
'
;
import
BoardContentSidebar
from
'
~/boards/components/board_content_sidebar.vue
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
...
...
@@ -35,20 +36,22 @@ describe('ee/BoardContent', () => {
});
describe
.
each
`
licenseEnabled | state | result
${
true
}
|
${{
isShowingEpicsSwimlanes
:
true
}
} |
${
true
}
${
true
}
|
${{
isShowingEpicsSwimlanes
:
false
}
} |
${
false
}
${
false
}
|
${{
isShowingEpicsSwimlanes
:
true
}
} |
${
false
}
${
false
}
|
${{
isShowingEpicsSwimlanes
:
false
}
} |
${
false
}
`
(
'
with licenseEnabled=$licenseEnabled and state=$state
'
,
({
licenseEnabled
,
state
,
result
})
=>
{
state | resultIssue | resultEpic
${{
isShowingEpicsSwimlanes
:
true
,
issuableType
:
'
issue
'
}
} |
${
true
}
|
${
false
}
${{
isShowingEpicsSwimlanes
:
false
,
issuableType
:
'
issue
'
}
} |
${
true
}
|
${
false
}
${{
isShowingEpicsSwimlanes
:
false
,
issuableType
:
'
epic
'
}
} |
${
false
}
|
${
true
}
`
(
'
with state=$state
'
,
({
state
,
resultIssue
,
resultEpic
})
=>
{
beforeEach
(()
=>
{
gon
.
licensed_features
.
swimlanes
=
licenseEnabled
;
Object
.
assign
(
store
.
state
,
state
);
createComponent
();
});
it
(
`renders BoardContentSidebar =
${
result
}
`
,
()
=>
{
expect
(
wrapper
.
find
(
BoardContentSidebar
).
exists
()).
toBe
(
result
);
it
(
`renders BoardContentSidebar =
${
resultIssue
}
`
,
()
=>
{
expect
(
wrapper
.
find
(
BoardContentSidebar
).
exists
()).
toBe
(
resultIssue
);
});
it
(
`renders EpicBoardContentSidebar =
${
resultEpic
}
`
,
()
=>
{
expect
(
wrapper
.
find
(
EpicBoardContentSidebar
).
exists
()).
toBe
(
resultEpic
);
});
});
});
ee/spec/frontend/boards/components/board_list_selector/board_list_selector_spec.js
View file @
cfccf903
...
...
@@ -11,11 +11,6 @@ import axios from '~/lib/utils/axios_utils';
jest
.
mock
(
'
~/flash
'
);
describe
(
'
BoardListSelector
'
,
()
=>
{
global
.
gon
.
features
=
{
...(
global
.
gon
.
features
||
{}),
graphqlBoardLists
:
false
,
};
const
dummyEndpoint
=
`
${
TEST_HOST
}
/users.json`
;
const
createComponent
=
()
=>
...
...
@@ -93,19 +88,7 @@ describe('BoardListSelector', () => {
});
describe
(
'
handleItemClick
'
,
()
=>
{
it
(
'
graphqlBoardLists FF off - creates new list in a store instance
'
,
()
=>
{
jest
.
spyOn
(
vm
.
store
,
'
new
'
).
mockReturnValue
({});
const
assignee
=
mockAssigneesList
[
0
];
expect
(
vm
.
store
.
findList
(
'
title
'
,
assignee
.
name
)).
not
.
toBeDefined
();
vm
.
handleItemClick
(
assignee
);
expect
(
vm
.
store
.
new
).
toHaveBeenCalledWith
(
expect
.
any
(
Object
));
});
it
(
'
graphqlBoardLists FF on - creates new list in a store instance
'
,
()
=>
{
global
.
gon
.
features
.
graphqlBoardLists
=
true
;
it
(
'
creates new list in a store instance
'
,
()
=>
{
jest
.
spyOn
(
vm
.
vuexStore
,
'
dispatch
'
).
mockReturnValue
({});
const
assignee
=
mockAssigneesList
[
0
];
...
...
ee/spec/frontend/boards/components/board_settings_sidebar_spec.js
View file @
cfccf903
import
'
~/boards/models/list
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
BoardSettingsListTypes
from
'
ee_component/boards/components/board_settings_list_types.vue
'
;
import
BoardSettingsWipLimit
from
'
ee_component/boards/components/board_settings_wip_limit.vue
'
;
import
{
mockLabelList
,
mockMilestoneList
}
from
'
jest/boards/mock_data
'
;
import
BoardSettingsSidebar
from
'
~/boards/components/board_settings_sidebar.vue
'
;
import
{
LIST
}
from
'
~/boards/constants
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
getters
from
'
~/boards/stores/getters
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
ee/BoardSettingsSidebar
'
,
()
=>
{
let
wrapper
;
let
storeActions
;
const
labelTitle
=
'
test
'
;
const
labelColor
=
'
#FFFF
'
;
const
listId
=
1
;
let
mock
;
const
createComponent
=
(
actions
=
{},
isWipLimitsOn
=
false
)
=>
{
const
createComponent
=
(
{
actions
=
{},
isWipLimitsOn
=
false
,
list
=
{}
}
)
=>
{
storeActions
=
actions
;
const
boardLists
=
{
[
list
.
id
]:
{
...
list
,
maxIssueCount
:
0
},
};
const
store
=
new
Vuex
.
Store
({
state
:
{
sidebarType
:
LIST
,
activeId
:
list
Id
},
state
:
{
sidebarType
:
LIST
,
activeId
:
list
.
id
,
boardLists
},
getters
,
actions
:
storeActions
,
});
wrapper
=
shallowMount
(
BoardSettingsSidebar
,
{
store
,
localVue
,
provide
:
{
glFeatures
:
{
wipLimits
:
isWipLimitsOn
,
...
...
@@ -47,41 +41,18 @@ describe('ee/BoardSettingsSidebar', () => {
});
};
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
boardsStore
.
create
();
});
afterEach
(()
=>
{
mock
.
restore
();
wrapper
.
destroy
();
});
it
(
'
confirms we render BoardSettingsSidebarWipLimit
'
,
()
=>
{
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
},
max_issue_count
:
0
,
list_type
:
'
label
'
,
});
createComponent
({},
true
);
createComponent
({
list
:
mockLabelList
,
isWipLimitsOn
:
true
});
expect
(
wrapper
.
find
(
BoardSettingsWipLimit
).
exists
()).
toBe
(
true
);
});
it
(
'
confirms we render BoardSettingsListTypes
'
,
()
=>
{
boardsStore
.
addList
({
id
:
1
,
milestone
:
{
webUrl
:
'
https://gitlab.com/h5bp/html5-boilerplate/-/milestones/1
'
,
title
:
'
Backlog
'
,
},
max_issue_count
:
1
,
list_type
:
'
milestone
'
,
});
createComponent
();
createComponent
({
list
:
mockMilestoneList
});
expect
(
wrapper
.
find
(
BoardSettingsListTypes
).
exists
()).
toBe
(
true
);
});
...
...
ee/spec/frontend/boards/components/board_settings_wip_limit_spec.js
View file @
cfccf903
import
'
~/boards/models/list
'
;
import
{
GlFormInput
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
noop
}
from
'
lodash
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
BoardSettingsWipLimit
from
'
ee_component/boards/components/board_settings_wip_limit.vue
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
{
mockLabelList
}
from
'
jest/boards/mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
BoardSettingsWipLimit
'
,
()
=>
{
let
wrapper
;
let
storeActions
;
const
labelTitle
=
'
test
'
;
const
labelColor
=
'
#FFFF
'
;
const
listId
=
1
;
const
listId
=
mockLabelList
.
id
;
const
currentWipLimit
=
1
;
// Needs to be other than null to trigger requests
let
mock
;
const
addList
=
(
maxIssueCount
=
0
)
=>
{
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
},
max_issue_count
:
maxIssueCount
,
list_type
:
'
label
'
,
});
};
const
clickEdit
=
()
=>
wrapper
.
find
(
'
.js-edit-button
'
).
vm
.
$emit
(
'
click
'
);
const
findRemoveWipLimit
=
()
=>
wrapper
.
find
(
'
.js-remove-limit
'
);
const
findWipLimit
=
()
=>
wrapper
.
find
(
'
.js-wip-limit
'
);
...
...
@@ -46,13 +31,11 @@ describe('BoardSettingsWipLimit', () => {
const
store
=
new
Vuex
.
Store
({
state
:
vuexState
,
actions
:
storeActions
,
getters
:
{
shouldUseGraphQL
:
()
=>
false
},
});
wrapper
=
shallowMount
(
BoardSettingsWipLimit
,
{
propsData
:
props
,
store
,
localVue
,
data
()
{
return
localState
;
},
...
...
@@ -69,13 +52,7 @@ describe('BoardSettingsWipLimit', () => {
}
};
beforeEach
(()
=>
{
boardsStore
.
create
();
mock
=
new
MockAdapter
(
axios
);
});
afterEach
(()
=>
{
mock
.
restore
();
jest
.
restoreAllMocks
();
wrapper
.
destroy
();
});
...
...
@@ -83,25 +60,28 @@ describe('BoardSettingsWipLimit', () => {
describe
(
'
when activeList is present
'
,
()
=>
{
describe
(
'
when activeListWipLimit is 0
'
,
()
=>
{
it
(
'
renders "None" in the block
'
,
()
=>
{
createComponent
({
vuexState
:
{
activeId
:
listId
}
});
createComponent
({
vuexState
:
{
activeId
:
listId
,
},
});
expect
(
findWipLimit
().
text
()).
toBe
(
'
None
'
);
});
});
describe
(
'
when activeId is greater than 0
'
,
()
=>
{
afterEach
(()
=>
{
boardsStore
.
removeList
(
listId
);
});
describe
(
'
when activeListWipLimit is greater than 0
'
,
()
=>
{
it
.
each
`
num | expected
${
1
}
|
${
'
1 issue
'
}
${
11
}
|
${
'
11 issues
'
}
`
(
'
it renders $num
'
,
({
num
,
expected
})
=>
{
addList
(
4
);
createComponent
({
vuexState
:
{
activeId
:
num
},
props
:
{
maxIssueCount
:
num
}
});
createComponent
({
vuexState
:
{
activeId
:
listId
,
},
props
:
{
maxIssueCount
:
num
},
});
expect
(
findWipLimit
().
text
()).
toBe
(
expected
);
});
...
...
@@ -112,7 +92,9 @@ describe('BoardSettingsWipLimit', () => {
const
maxIssueCount
=
4
;
beforeEach
(
async
()
=>
{
createComponent
({
vuexState
:
{
activeId
:
listId
},
vuexState
:
{
activeId
:
listId
,
},
actions
:
{
updateListWipLimit
:
noop
},
props
:
{
maxIssueCount
},
});
...
...
@@ -137,15 +119,14 @@ describe('BoardSettingsWipLimit', () => {
describe
(
'
remove limit
'
,
()
=>
{
describe
(
'
when wipLimit is set
'
,
()
=>
{
beforeEach
(()
=>
{
addList
(
4
);
const
spy
=
jest
.
fn
().
mockResolvedValue
({
config
:
{
data
:
JSON
.
stringify
({
list
:
{
max_issue_count
:
0
}
})
},
data
:
{
boardListUpdateLimitMetrics
:
{
list
:
{
maxIssueCount
:
0
}
}
},
});
beforeEach
(()
=>
{
createComponent
({
vuexState
:
{
activeId
:
listId
},
vuexState
:
{
activeId
:
listId
,
},
actions
:
{
updateListWipLimit
:
spy
},
props
:
{
maxIssueCount
:
4
},
});
...
...
@@ -156,18 +137,22 @@ describe('BoardSettingsWipLimit', () => {
findRemoveWipLimit
().
vm
.
$emit
(
'
click
'
);
await
waitForPromises
();
await
wrapper
.
vm
.
$nextTick
();
// WARNING: https://gitlab.com/gitlab-org/gitlab/-/issues/232573
expect
(
boardsStore
.
findList
(
'
id
'
,
listId
).
maxIssueCount
).
toBe
(
0
);
expect
(
spy
).
toHaveBeenCalledWith
(
expect
.
anything
(),
expect
.
objectContaining
({
listId
,
maxIssueCount
:
0
}),
);
});
});
describe
(
'
when wipLimit is not set
'
,
()
=>
{
beforeEach
(()
=>
{
addList
();
createComponent
({
vuexState
:
{
activeId
:
listId
},
actions
:
{
updateListWipLimit
:
noop
}
});
createComponent
({
vuexState
:
{
activeId
:
listId
},
actions
:
{
updateListWipLimit
:
noop
},
});
});
it
(
'
does not render the remove limit button
'
,
()
=>
{
...
...
@@ -177,14 +162,6 @@ describe('BoardSettingsWipLimit', () => {
});
describe
(
'
when edit is true
'
,
()
=>
{
beforeEach
(()
=>
{
addList
(
2
);
});
afterEach
(()
=>
{
boardsStore
.
removeList
(
listId
);
});
describe
.
each
`
blurMethod
${
'
enter
'
}
...
...
@@ -193,10 +170,12 @@ describe('BoardSettingsWipLimit', () => {
describe
(
`when blur is triggered by
${
blurMethod
}
`
,
()
=>
{
it
(
'
calls updateListWipLimit
'
,
async
()
=>
{
const
spy
=
jest
.
fn
().
mockResolvedValue
({
config
:
{
data
:
JSON
.
stringify
({
list
:
{
max_issue_count
:
'
4
'
}
})
},
data
:
{
boardListUpdateLimitMetrics
:
{
list
:
{
maxIssueCount
:
4
}
}
},
});
createComponent
({
vuexState
:
{
activeId
:
listId
},
vuexState
:
{
activeId
:
listId
,
},
actions
:
{
updateListWipLimit
:
spy
},
localState
:
{
edit
:
true
,
currentWipLimit
},
});
...
...
@@ -209,10 +188,12 @@ describe('BoardSettingsWipLimit', () => {
});
describe
(
'
when component wipLimit and List.maxIssueCount are equal
'
,
()
=>
{
it
(
'
does
n
t call updateListWipLimit
'
,
async
()
=>
{
it
(
'
does
no
t call updateListWipLimit
'
,
async
()
=>
{
const
spy
=
jest
.
fn
().
mockResolvedValue
({});
createComponent
({
vuexState
:
{
activeId
:
listId
},
vuexState
:
{
activeId
:
listId
,
},
actions
:
{
updateListWipLimit
:
spy
},
localState
:
{
edit
:
true
,
currentWipLimit
:
2
},
props
:
{
maxIssueCount
:
2
},
...
...
@@ -227,7 +208,7 @@ describe('BoardSettingsWipLimit', () => {
});
describe
(
'
when currentWipLimit is null
'
,
()
=>
{
it
(
'
does
n
t call updateListWipLimit
'
,
async
()
=>
{
it
(
'
does
no
t call updateListWipLimit
'
,
async
()
=>
{
const
spy
=
jest
.
fn
().
mockResolvedValue
({});
createComponent
({
vuexState
:
{
activeId
:
listId
},
...
...
@@ -249,9 +230,12 @@ describe('BoardSettingsWipLimit', () => {
beforeEach
(()
=>
{
const
spy
=
jest
.
fn
().
mockResolvedValue
({});
createComponent
({
vuexState
:
{
activeId
:
listId
},
vuexState
:
{
activeId
:
listId
,
},
actions
:
{
updateListWipLimit
:
spy
},
localState
:
{
edit
:
true
,
currentWipLimit
:
maxIssueCount
},
props
:
{
maxIssueCount
},
});
triggerBlur
(
blurMethod
);
...
...
@@ -260,14 +244,7 @@ describe('BoardSettingsWipLimit', () => {
});
it
(
'
sets activeWipLimit to new maxIssueCount value
'
,
()
=>
{
/*
* DANGER: bad coupling to the computed prop of the component because the
* computed prop relys on the list from boardStore, for now this is the way around
* stale values from boardsStore being updated, when we move List and BoardsStore to Vuex
* or Graphql we will be able to query the DOM for the new value.
*/
expect
(
boardsStore
.
findList
(
'
id
'
,
1
).
maxIssueCount
).
toBe
(
maxIssueCount
);
expect
(
findWipLimit
().
text
()).
toContain
(
maxIssueCount
);
});
it
(
'
toggles GlFormInput on blur
'
,
()
=>
{
...
...
ee/spec/frontend/boards/stores/actions_spec.js
View file @
cfccf903
...
...
@@ -112,12 +112,7 @@ describe('setFilters', () => {
});
describe
(
'
performSearch
'
,
()
=>
{
it
(
'
should dispatch setFilters action
'
,
(
done
)
=>
{
testAction
(
actions
.
performSearch
,
{},
{},
[],
[{
type
:
'
setFilters
'
,
payload
:
{}
}],
done
);
});
it
(
'
should dispatch setFilters, fetchLists and resetIssues action when graphqlBoardLists FF is on
'
,
async
()
=>
{
window
.
gon
=
{
features
:
{
graphqlBoardLists
:
true
}
};
it
(
'
should dispatch setFilters, fetchLists and resetIssues action
'
,
async
()
=>
{
const
getters
=
{
isSwimlanesOn
:
false
};
await
testAction
({
...
...
@@ -139,9 +134,9 @@ describe('performSearch', () => {
expectedActions
:
[
{
type
:
'
setFilters
'
,
payload
:
{}
},
{
type
:
'
resetEpics
'
},
{
type
:
'
resetIssues
'
},
{
type
:
'
fetchEpicsSwimlanes
'
},
{
type
:
'
fetchLists
'
},
{
type
:
'
resetIssues
'
},
],
});
});
...
...
@@ -464,7 +459,6 @@ describe('setShowLabels', () => {
describe
(
'
updateListWipLimit
'
,
()
=>
{
let
storeMock
;
const
getters
=
{
shouldUseGraphQL
:
false
};
beforeEach
(()
=>
{
storeMock
=
{
...
...
@@ -483,26 +477,9 @@ describe('updateListWipLimit', () => {
jest
.
restoreAllMocks
();
});
it
(
'
axios - should call the correct url
'
,
()
=>
{
const
maxIssueCount
=
0
;
const
activeId
=
1
;
return
actions
.
updateListWipLimit
({
state
:
{
activeId
},
getters
},
{
maxIssueCount
,
listId
:
activeId
})
.
then
(()
=>
{
expect
(
axios
.
put
).
toHaveBeenCalledWith
(
`
${
boardsStoreEE
.
store
.
state
.
endpoints
.
listsEndpoint
}
/
${
activeId
}
`
,
{
list
:
{
max_issue_count
:
maxIssueCount
},
},
);
});
});
it
(
'
graphql - commit UPDATE_LIST_SUCCESS mutation on success
'
,
()
=>
{
it
(
'
commit UPDATE_LIST_SUCCESS mutation on success
'
,
()
=>
{
const
maxIssueCount
=
0
;
const
activeId
=
1
;
getters
.
shouldUseGraphQL
=
true
;
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
boardListUpdateLimitMetrics
:
{
...
...
@@ -517,7 +494,7 @@ describe('updateListWipLimit', () => {
return
testAction
(
actions
.
updateListWipLimit
,
{
maxIssueCount
,
listId
:
activeId
},
{
isShowingEpicsSwimlanes
:
true
,
...
getters
},
{
isShowingEpicsSwimlanes
:
true
},
[
{
type
:
types
.
UPDATE_LIST_SUCCESS
,
...
...
@@ -533,16 +510,15 @@ describe('updateListWipLimit', () => {
);
});
it
(
'
graphql -
dispatch handleUpdateListFailure on failure
'
,
()
=>
{
it
(
'
dispatch handleUpdateListFailure on failure
'
,
()
=>
{
const
maxIssueCount
=
0
;
const
activeId
=
1
;
getters
.
shouldUseGraphQL
=
true
;
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
(
Promise
.
reject
());
return
testAction
(
actions
.
updateListWipLimit
,
{
maxIssueCount
,
listId
:
activeId
},
{
isShowingEpicsSwimlanes
:
true
,
...
getters
},
{
isShowingEpicsSwimlanes
:
true
},
[],
[{
type
:
'
handleUpdateListFailure
'
}],
);
...
...
locale/gitlab.pot
View file @
cfccf903
...
...
@@ -3626,9 +3626,6 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
...
...
@@ -5513,9 +5510,6 @@ msgid_plural "Boards|Blocked by %{blockedByCount} %{issuableType}s"
msgstr[0] ""
msgstr[1] ""
msgid "Boards|Board"
msgstr ""
msgid "Boards|Collapse"
msgstr ""
...
...
spec/features/boards/multi_select_spec.rb
View file @
cfccf903
...
...
@@ -43,12 +43,12 @@ RSpec.describe 'Multi Select Issue', :js do
# Multi select drag&drop support is temporarily disabled
# https://gitlab.com/gitlab-org/gitlab/-/issues/289797
stub_feature_flags
(
graphql_board_lists:
false
,
board_multi_select:
project
)
stub_feature_flags
(
board_multi_select:
project
)
sign_in
(
user
)
end
context
'with lists'
do
x
context
'with lists'
do
let
(
:label1
)
{
create
(
:label
,
project:
project
,
name:
'Label 1'
,
description:
'Test'
)
}
let
(
:label2
)
{
create
(
:label
,
project:
project
,
name:
'Label 2'
,
description:
'Test'
)
}
let!
(
:list1
)
{
create
(
:list
,
board:
board
,
label:
label1
,
position:
0
)
}
...
...
spec/features/boards/sidebar_labels_spec.rb
View file @
cfccf903
...
...
@@ -5,8 +5,9 @@ require 'spec_helper'
RSpec
.
describe
'Project issue boards sidebar labels'
,
:js
do
include
BoardHelpers
let_it_be
(
:group
)
{
create
(
:group
,
:public
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
namespace:
group
)
}
let_it_be
(
:development
)
{
create
(
:label
,
project:
project
,
name:
'Development'
)
}
let_it_be
(
:bug
)
{
create
(
:label
,
project:
project
,
name:
'Bug'
)
}
let_it_be
(
:regression
)
{
create
(
:label
,
project:
project
,
name:
'Regression'
)
}
...
...
spec/features/boards/user_adds_lists_to_board_spec.rb
View file @
cfccf903
...
...
@@ -3,8 +3,6 @@
require
'spec_helper'
RSpec
.
describe
'User adds lists'
,
:js
do
using
RSpec
::
Parameterized
::
TableSyntax
let_it_be
(
:group
)
{
create
(
:group
,
:nested
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
namespace:
group
)
}
let_it_be
(
:group_board
)
{
create
(
:board
,
group:
group
)
}
...
...
@@ -27,11 +25,8 @@ RSpec.describe 'User adds lists', :js do
group
.
add_owner
(
user
)
end
where
(
:board_type
,
:graphql_board_lists_enabled
)
do
:project
|
true
:project
|
false
:group
|
true
:group
|
false
where
(
:board_type
)
do
[[
:project
],
[
:group
]]
end
with_them
do
...
...
@@ -40,10 +35,6 @@ RSpec.describe 'User adds lists', :js do
set_cookie
(
'sidebar_collapsed'
,
'true'
)
stub_feature_flags
(
graphql_board_lists:
graphql_board_lists_enabled
)
if
board_type
==
:project
visit
project_board_path
(
project
,
project_board
)
elsif
board_type
==
:group
...
...
@@ -53,14 +44,12 @@ RSpec.describe 'User adds lists', :js do
wait_for_all_requests
end
it
'creates new column for label containing labeled issue'
do
it
'creates new column for label containing labeled issue'
,
:aggregate_failures
do
click_button
'Create list'
wait_for_all_requests
select_label
(
group_label
)
wait_for_all_requests
expect
(
page
).
to
have_selector
(
'.board'
,
text:
group_label
.
title
)
expect
(
find
(
'.board:nth-child(2) .board-card'
)).
to
have_content
(
issue
.
title
)
end
...
...
spec/features/groups/board_sidebar_spec.rb
View file @
cfccf903
...
...
@@ -42,30 +42,4 @@ RSpec.describe 'Group Issue Boards', :js do
end
end
end
context
'when graphql_board_lists FF disabled'
do
before
do
stub_feature_flags
(
graphql_board_lists:
false
)
sign_in
(
user
)
visit
group_board_path
(
group
,
board
)
wait_for_requests
end
it
'only shows valid labels for the issue project and group'
do
click_card
(
card
)
page
.
within
(
'.labels'
)
do
click_link
'Edit'
wait_for_requests
page
.
within
(
'.selectbox'
)
do
expect
(
page
).
to
have_content
(
project_1_label
.
title
)
expect
(
page
).
to
have_content
(
group_label
.
title
)
expect
(
page
).
not_to
have_content
(
project_2_label
.
title
)
end
end
end
end
end
spec/features/labels_hierarchy_spec.rb
View file @
cfccf903
...
...
@@ -214,44 +214,6 @@ RSpec.describe 'Labels Hierarchy', :js do
end
end
context
'issuable sidebar when graphql_board_lists FF disabled'
do
let!
(
:issue
)
{
create
(
:issue
,
project:
project_1
)
}
before
do
stub_feature_flags
(
graphql_board_lists:
false
)
end
context
'on project board issue sidebar'
do
before
do
project_1
.
add_developer
(
user
)
board
=
create
(
:board
,
project:
project_1
)
visit
project_board_path
(
project_1
,
board
)
wait_for_requests
find
(
'.board-card'
).
click
end
it_behaves_like
'assigning labels from sidebar'
end
context
'on group board issue sidebar'
do
before
do
parent
.
add_developer
(
user
)
board
=
create
(
:board
,
group:
parent
)
visit
group_board_path
(
parent
,
board
)
wait_for_requests
find
(
'.board-card'
).
click
end
it_behaves_like
'assigning labels from sidebar'
end
end
context
'issuable filtering'
do
let!
(
:labeled_issue
)
{
create
(
:labeled_issue
,
project:
project_1
,
labels:
[
grandparent_group_label
,
parent_group_label
,
project_label_1
])
}
let!
(
:issue
)
{
create
(
:issue
,
project:
project_1
)
}
...
...
spec/frontend/boards/components/board_add_new_column_spec.js
View file @
cfccf903
...
...
@@ -48,7 +48,6 @@ describe('Board card layout', () => {
...
actions
,
},
getters
:
{
shouldUseGraphQL
:
()
=>
true
,
getListByLabelId
:
()
=>
getListByLabelId
,
},
state
:
{
...
...
spec/frontend/boards/components/board_card_deprecated_spec.js
View file @
cfccf903
...
...
@@ -8,7 +8,6 @@ import MockAdapter from 'axios-mock-adapter';
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
BoardCardDeprecated
from
'
~/boards/components/board_card_deprecated.vue
'
;
import
issueCardInner
from
'
~/boards/components/issue_card_inner_deprecated.vue
'
;
import
eventHub
from
'
~/boards/eventhub
'
;
import
store
from
'
~/boards/stores
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
...
...
@@ -165,46 +164,9 @@ describe('BoardCard', () => {
expect
(
boardsStore
.
detail
.
issue
).
toEqual
({});
});
it
(
'
sets detail issue to card issue on mouse up
'
,
()
=>
{
jest
.
spyOn
(
eventHub
,
'
$emit
'
).
mockImplementation
(()
=>
{});
mountComponent
();
wrapper
.
trigger
(
'
mousedown
'
);
wrapper
.
trigger
(
'
mouseup
'
);
expect
(
eventHub
.
$emit
).
toHaveBeenCalledWith
(
'
newDetailIssue
'
,
wrapper
.
vm
.
issue
,
false
);
expect
(
boardsStore
.
detail
.
list
).
toEqual
(
wrapper
.
vm
.
list
);
});
it
(
'
resets detail issue to empty if already set
'
,
()
=>
{
jest
.
spyOn
(
eventHub
,
'
$emit
'
).
mockImplementation
(()
=>
{});
const
[
issue
]
=
list
.
issues
;
boardsStore
.
detail
.
issue
=
issue
;
mountComponent
();
wrapper
.
trigger
(
'
mousedown
'
);
wrapper
.
trigger
(
'
mouseup
'
);
expect
(
eventHub
.
$emit
).
toHaveBeenCalledWith
(
'
clearDetailIssue
'
,
false
);
});
});
describe
(
'
sidebarHub events
'
,
()
=>
{
it
(
'
closes all sidebars before showing an issue if no issues are opened
'
,
()
=>
{
jest
.
spyOn
(
sidebarEventHub
,
'
$emit
'
).
mockImplementation
(()
=>
{});
boardsStore
.
detail
.
issue
=
{};
mountComponent
();
// sets conditional so that event is emitted.
wrapper
.
trigger
(
'
mousedown
'
);
wrapper
.
trigger
(
'
mouseup
'
);
expect
(
sidebarEventHub
.
$emit
).
toHaveBeenCalledWith
(
'
sidebar.closeAll
'
);
});
it
(
'
it does not closes all sidebars before showing an issue if an issue is opened
'
,
()
=>
{
jest
.
spyOn
(
sidebarEventHub
,
'
$emit
'
).
mockImplementation
(()
=>
{});
const
[
issue
]
=
list
.
issues
;
...
...
spec/frontend/boards/components/board_card_layout_deprecated_spec.js
View file @
cfccf903
...
...
@@ -111,18 +111,14 @@ describe('Board card layout', () => {
expect
(
wrapper
.
vm
.
showDetail
).
toBe
(
false
);
});
it
(
"
calls 'setActiveId'
when 'graphqlBoardLists' feature flag is turned on
"
,
async
()
=>
{
it
(
"
calls 'setActiveId'
"
,
async
()
=>
{
const
setActiveId
=
jest
.
fn
();
createStore
({
actions
:
{
setActiveId
,
},
});
mountComponent
({
provide
:
{
glFeatures
:
{
graphqlBoardLists
:
true
},
},
});
mountComponent
();
wrapper
.
trigger
(
'
mouseup
'
);
await
wrapper
.
vm
.
$nextTick
();
...
...
spec/frontend/boards/components/board_content_spec.js
View file @
cfccf903
...
...
@@ -5,7 +5,7 @@ import Draggable from 'vuedraggable';
import
Vuex
from
'
vuex
'
;
import
EpicsSwimlanes
from
'
ee_component/boards/components/epics_swimlanes.vue
'
;
import
getters
from
'
ee_else_ce/boards/stores/getters
'
;
import
BoardColumn
Deprecated
from
'
~/boards/components/board_column_deprecated
.vue
'
;
import
BoardColumn
from
'
~/boards/components/board_column
.vue
'
;
import
BoardContent
from
'
~/boards/components/board_content.vue
'
;
import
{
mockLists
,
mockListsWithModel
}
from
'
../mock_data
'
;
...
...
@@ -33,12 +33,7 @@ describe('BoardContent', () => {
});
};
const
createComponent
=
({
state
,
props
=
{},
graphqlBoardListsEnabled
=
false
,
canAdminList
=
true
,
}
=
{})
=>
{
const
createComponent
=
({
state
,
props
=
{},
canAdminList
=
true
}
=
{})
=>
{
const
store
=
createStore
({
...
defaultState
,
...
state
,
...
...
@@ -51,42 +46,31 @@ describe('BoardContent', () => {
},
provide
:
{
canAdminList
,
glFeatures
:
{
graphqlBoardLists
:
graphqlBoardListsEnabled
},
},
store
,
});
};
beforeEach
(()
=>
{
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
renders a BoardColumnDeprecated component per list
'
,
()
=>
{
createComponent
();
expect
(
wrapper
.
findAllComponents
(
BoardColumnDeprecated
)).
toHaveLength
(
mockListsWithModel
.
length
,
);
it
(
'
renders a BoardColumn component per list
'
,
()
=>
{
expect
(
wrapper
.
findAllComponents
(
BoardColumn
)).
toHaveLength
(
mockListsWithModel
.
length
);
});
it
(
'
does not display EpicsSwimlanes component
'
,
()
=>
{
createComponent
();
expect
(
wrapper
.
find
(
EpicsSwimlanes
).
exists
()).
toBe
(
false
);
expect
(
wrapper
.
find
(
GlAlert
).
exists
()).
toBe
(
false
);
});
describe
(
'
graphqlBoardLists feature flag enabled
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
});
gon
.
features
=
{
graphqlBoardLists
:
true
,
};
});
describe
(
'
can admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
,
canAdminList
:
true
});
createComponent
({
canAdminList
:
true
});
});
it
(
'
renders draggable component
'
,
()
=>
{
...
...
@@ -96,18 +80,7 @@ describe('BoardContent', () => {
describe
(
'
can not admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
,
canAdminList
:
false
});
});
it
(
'
does not render draggable component
'
,
()
=>
{
expect
(
wrapper
.
find
(
Draggable
).
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
graphqlBoardLists feature flag disabled
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
false
});
createComponent
({
canAdminList
:
false
});
});
it
(
'
does not render draggable component
'
,
()
=>
{
...
...
spec/frontend/boards/components/board_filtered_search_spec.js
View file @
cfccf903
...
...
@@ -2,7 +2,6 @@ import { shallowMount } from '@vue/test-utils';
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
BoardFilteredSearch
from
'
~/boards/components/board_filtered_search.vue
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
*
as
urlUtility
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
FilteredSearchBarRoot
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
...
...
@@ -44,6 +43,12 @@ describe('BoardFilteredSearch', () => {
];
const
createComponent
=
({
initialFilterParams
=
{}
}
=
{})
=>
{
store
=
new
Vuex
.
Store
({
actions
:
{
performSearch
:
jest
.
fn
(),
},
});
wrapper
=
shallowMount
(
BoardFilteredSearch
,
{
provide
:
{
initialFilterParams
,
fullPath
:
''
},
store
,
...
...
@@ -55,22 +60,15 @@ describe('BoardFilteredSearch', () => {
const
findFilteredSearch
=
()
=>
wrapper
.
findComponent
(
FilteredSearchBarRoot
);
beforeEach
(()
=>
{
// this needed for actions call for performSearch
window
.
gon
=
{
features
:
{}
};
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
default
'
,
()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
createComponent
();
jest
.
spyOn
(
store
,
'
dispatch
'
);
createComponent
();
});
it
(
'
renders FilteredSearch
'
,
()
=>
{
...
...
@@ -103,8 +101,6 @@ describe('BoardFilteredSearch', () => {
describe
(
'
when searching
'
,
()
=>
{
beforeEach
(()
=>
{
store
=
createStore
();
createComponent
();
jest
.
spyOn
(
wrapper
.
vm
,
'
performSearch
'
).
mockImplementation
();
...
...
@@ -133,11 +129,9 @@ describe('BoardFilteredSearch', () => {
describe
(
'
when url params are already set
'
,
()
=>
{
beforeEach
(()
=>
{
store
=
createStore
(
);
createComponent
({
initialFilterParams
:
{
authorUsername
:
'
root
'
,
labelName
:
[
'
label
'
]
}
}
);
jest
.
spyOn
(
store
,
'
dispatch
'
);
createComponent
({
initialFilterParams
:
{
authorUsername
:
'
root
'
,
labelName
:
[
'
label
'
]
}
});
});
it
(
'
passes the correct props to FilterSearchBar
'
,
()
=>
{
...
...
spec/frontend/boards/components/board_settings_sidebar_spec.js
View file @
cfccf903
import
'
~/boards/models/list
'
;
import
{
GlDrawer
,
GlLabel
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
axios
from
'
axios
'
;
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
MountingPortal
}
from
'
portal-vue
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
BoardSettingsSidebar
from
'
~/boards/components/board_settings_sidebar.vue
'
;
import
{
inactiveId
,
LIST
}
from
'
~/boards/constants
'
;
import
{
createStore
}
from
'
~/boards/stores
'
;
import
boardsStore
from
'
~/boards/stores/boards_store
'
;
import
actions
from
'
~/boards/stores/actions
'
;
import
getters
from
'
~/boards/stores/getters
'
;
import
mutations
from
'
~/boards/stores/mutations
'
;
import
sidebarEventHub
from
'
~/sidebar/event_hub
'
;
import
{
mockLabelList
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
Vue
.
use
(
Vuex
);
describe
(
'
BoardSettingsSidebar
'
,
()
=>
{
let
wrapper
;
let
mock
;
let
store
;
const
labelTitle
=
'
test
'
;
const
labelColor
=
'
#FFFF
'
;
const
listId
=
1
;
const
labelTitle
=
mockLabelList
.
label
.
title
;
const
labelColor
=
mockLabelList
.
label
.
color
;
const
listId
=
mockLabelList
.
id
;
const
findRemoveButton
=
()
=>
wrapper
.
findByTestId
(
'
remove-list
'
);
const
createComponent
=
({
canAdminList
=
false
}
=
{})
=>
{
const
createComponent
=
({
canAdminList
=
false
,
list
=
{},
sidebarType
=
LIST
,
activeId
=
inactiveId
,
}
=
{})
=>
{
const
boardLists
=
{
[
listId
]:
list
,
};
const
store
=
new
Vuex
.
Store
({
state
:
{
sidebarType
,
activeId
,
boardLists
},
getters
,
mutations
,
actions
,
});
wrapper
=
extendedWrapper
(
shallowMount
(
BoardSettingsSidebar
,
{
store
,
localVue
,
provide
:
{
canAdminList
,
},
...
...
@@ -40,16 +51,10 @@ describe('BoardSettingsSidebar', () => {
const
findLabel
=
()
=>
wrapper
.
find
(
GlLabel
);
const
findDrawer
=
()
=>
wrapper
.
find
(
GlDrawer
);
beforeEach
(()
=>
{
store
=
createStore
();
store
.
state
.
activeId
=
inactiveId
;
store
.
state
.
sidebarType
=
LIST
;
boardsStore
.
create
();
});
afterEach
(()
=>
{
jest
.
restoreAllMocks
();
wrapper
.
destroy
();
wrapper
=
null
;
});
it
(
'
finds a MountingPortal component
'
,
()
=>
{
...
...
@@ -100,86 +105,40 @@ describe('BoardSettingsSidebar', () => {
});
describe
(
'
when activeId is greater than zero
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
},
list_type
:
'
label
'
,
});
store
.
state
.
activeId
=
1
;
store
.
state
.
sidebarType
=
LIST
;
});
afterEach
(()
=>
{
boardsStore
.
removeList
(
listId
);
});
it
(
'
renders GlDrawer with open false
'
,
()
=>
{
createComponent
();
it
(
'
renders GlDrawer with open true
'
,
()
=>
{
createComponent
({
list
:
mockLabelList
,
activeId
:
listId
});
expect
(
findDrawer
().
props
(
'
open
'
)).
toBe
(
true
);
});
});
describe
(
'
when activeId is in boardsStore
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
},
list_type
:
'
label
'
,
});
store
.
state
.
activeId
=
listId
;
store
.
state
.
sidebarType
=
LIST
;
createComponent
();
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
when activeId is in state
'
,
()
=>
{
it
(
'
renders label title
'
,
()
=>
{
createComponent
({
list
:
mockLabelList
,
activeId
:
listId
});
expect
(
findLabel
().
props
(
'
title
'
)).
toBe
(
labelTitle
);
});
it
(
'
renders label background color
'
,
()
=>
{
expect
(
findLabel
().
props
(
'
backgroundColor
'
)).
toBe
(
labelColor
);
});
});
describe
(
'
when activeId is not in boardsStore
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
createComponent
({
list
:
mockLabelList
,
activeId
:
listId
});
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
}
});
store
.
state
.
activeId
=
inactiveId
;
createComponent
();
expect
(
findLabel
().
props
(
'
backgroundColor
'
)).
toBe
(
labelColor
);
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
when activeId is not in state
'
,
()
=>
{
it
(
'
does not render GlLabel
'
,
()
=>
{
createComponent
({
list
:
mockLabelList
});
expect
(
findLabel
().
exists
()).
toBe
(
false
);
});
});
});
describe
(
'
when sidebarType is not List
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
sidebarType
=
''
;
createComponent
();
});
it
(
'
does not render GlDrawer
'
,
()
=>
{
createComponent
({
sidebarType
:
''
});
expect
(
findDrawer
().
exists
()).
toBe
(
false
);
});
});
...
...
@@ -191,20 +150,9 @@ describe('BoardSettingsSidebar', () => {
});
describe
(
'
when user can admin the boards list
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
activeId
=
listId
;
store
.
state
.
sidebarType
=
LIST
;
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
},
list_type
:
'
label
'
,
});
createComponent
({
canAdminList
:
true
});
});
it
(
'
renders "Remove list" button
'
,
()
=>
{
createComponent
({
canAdminList
:
true
,
activeId
:
listId
,
list
:
mockLabelList
});
expect
(
findRemoveButton
().
exists
()).
toBe
(
true
);
});
});
...
...
spec/frontend/boards/mock_data.js
View file @
cfccf903
...
...
@@ -336,6 +336,22 @@ export const mockLabelList = {
issuesCount
:
0
,
};
export
const
mockMilestoneList
=
{
id
:
'
gid://gitlab/List/3
'
,
title
:
'
To Do
'
,
position
:
0
,
listType
:
'
milestone
'
,
collapsed
:
false
,
label
:
null
,
assignee
:
null
,
milestone
:
{
webUrl
:
'
https://gitlab.com/h5bp/html5-boilerplate/-/milestones/1
'
,
title
:
'
Backlog
'
,
},
loading
:
false
,
issuesCount
:
0
,
};
export
const
mockLists
=
[
mockList
,
mockLabelList
];
export
const
mockListsById
=
keyBy
(
mockLists
,
'
id
'
);
...
...
spec/frontend/boards/stores/actions_spec.js
View file @
cfccf903
...
...
@@ -107,12 +107,7 @@ describe('setFilters', () => {
});
describe
(
'
performSearch
'
,
()
=>
{
it
(
'
should dispatch setFilters action
'
,
(
done
)
=>
{
testAction
(
actions
.
performSearch
,
{},
{},
[],
[{
type
:
'
setFilters
'
,
payload
:
{}
}],
done
);
});
it
(
'
should dispatch setFilters, fetchLists and resetIssues action when graphqlBoardLists FF is on
'
,
(
done
)
=>
{
window
.
gon
=
{
features
:
{
graphqlBoardLists
:
true
}
};
it
(
'
should dispatch setFilters, fetchLists and resetIssues action
'
,
(
done
)
=>
{
testAction
(
actions
.
performSearch
,
{},
...
...
@@ -496,12 +491,9 @@ describe('fetchLabels', () => {
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
commit
=
jest
.
fn
();
const
getters
=
{
shouldUseGraphQL
:
()
=>
true
,
};
const
state
=
{
boardType
:
'
group
'
};
await
actions
.
fetchLabels
({
getters
,
state
,
commit
});
await
actions
.
fetchLabels
({
state
,
commit
});
expect
(
commit
).
toHaveBeenCalledWith
(
types
.
RECEIVE_LABELS_SUCCESS
,
labels
);
});
...
...
@@ -954,7 +946,7 @@ describe('moveIssue', () => {
});
describe
(
'
moveIssueCard and undoMoveIssueCard
'
,
()
=>
{
describe
(
'
card should move without clon
n
ing
'
,
()
=>
{
describe
(
'
card should move without cloning
'
,
()
=>
{
let
state
;
let
params
;
let
moveMutations
;
...
...
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