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
e9900469
Commit
e9900469
authored
Aug 31, 2021
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
7f3527b1
0a315e69
Changes
73
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
73 changed files
with
357 additions
and
1414 deletions
+357
-1414
.rubocop_manual_todo.yml
.rubocop_manual_todo.yml
+0
-25
GITALY_SERVER_VERSION
GITALY_SERVER_VERSION
+1
-1
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/graphql/types/repository/blob_type.rb
app/graphql/types/repository/blob_type.rb
+3
-3
app/graphql/types/root_storage_statistics_type.rb
app/graphql/types/root_storage_statistics_type.rb
+9
-9
app/graphql/types/snippet_type.rb
app/graphql/types/snippet_type.rb
+2
-2
app/graphql/types/snippets/blob_type.rb
app/graphql/types/snippets/blob_type.rb
+1
-1
app/graphql/types/snippets/visibility_scopes_enum.rb
app/graphql/types/snippets/visibility_scopes_enum.rb
+3
-3
app/graphql/types/terraform/state_type.rb
app/graphql/types/terraform/state_type.rb
+2
-2
app/graphql/types/terraform/state_version_type.rb
app/graphql/types/terraform/state_version_type.rb
+2
-2
app/graphql/types/timelog_type.rb
app/graphql/types/timelog_type.rb
+6
-6
app/graphql/types/todo_state_enum.rb
app/graphql/types/todo_state_enum.rb
+2
-2
app/graphql/types/todo_target_enum.rb
app/graphql/types/todo_target_enum.rb
+5
-5
app/graphql/types/todo_type.rb
app/graphql/types/todo_type.rb
+2
-2
app/graphql/types/user_interface.rb
app/graphql/types/user_interface.rb
+1
-1
app/graphql/types/user_merge_request_interaction_type.rb
app/graphql/types/user_merge_request_interaction_type.rb
+1
-1
app/graphql/types/user_state_enum.rb
app/graphql/types/user_state_enum.rb
+3
-3
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/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+63
-63
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/app/graphql/ee/mutations/alert_management/http_integration/create.rb
.../ee/mutations/alert_management/http_integration/create.rb
+2
-2
ee/app/graphql/ee/mutations/alert_management/http_integration/update.rb
.../ee/mutations/alert_management/http_integration/update.rb
+2
-2
ee/app/graphql/ee/mutations/issues/create.rb
ee/app/graphql/ee/mutations/issues/create.rb
+1
-1
ee/app/graphql/ee/mutations/issues/update.rb
ee/app/graphql/ee/mutations/issues/update.rb
+1
-1
ee/app/graphql/ee/types/alert_management/http_integration_type.rb
...raphql/ee/types/alert_management/http_integration_type.rb
+1
-1
ee/app/graphql/ee/types/board_list_type.rb
ee/app/graphql/ee/types/board_list_type.rb
+1
-1
ee/app/graphql/ee/types/board_type.rb
ee/app/graphql/ee/types/board_type.rb
+3
-3
ee/app/graphql/ee/types/group_type.rb
ee/app/graphql/ee/types/group_type.rb
+2
-2
ee/app/graphql/ee/types/project_type.rb
ee/app/graphql/ee/types/project_type.rb
+3
-3
ee/app/graphql/ee/types/query_type.rb
ee/app/graphql/ee/types/query_type.rb
+2
-2
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.
.rubocop_manual_todo.yml
View file @
e9900469
...
...
@@ -23,31 +23,6 @@ Graphql/Descriptions:
-
'
ee/app/graphql/types/vulnerability_severity_enum.rb'
-
'
ee/app/graphql/types/vulnerability_state_enum.rb'
-
'
ee/app/graphql/types/vulnerability_confidence_enum.rb'
-
'
app/graphql/types/repository/blob_type.rb'
-
'
app/graphql/types/root_storage_statistics_type.rb'
-
'
app/graphql/types/snippet_type.rb'
-
'
app/graphql/types/snippets/blob_type.rb'
-
'
app/graphql/types/snippets/visibility_scopes_enum.rb'
-
'
app/graphql/types/terraform/state_type.rb'
-
'
app/graphql/types/terraform/state_version_type.rb'
-
'
app/graphql/types/timelog_type.rb'
-
'
app/graphql/types/todo_state_enum.rb'
-
'
app/graphql/types/todo_target_enum.rb'
-
'
app/graphql/types/todo_type.rb'
-
'
app/graphql/types/user_interface.rb'
-
'
app/graphql/types/user_merge_request_interaction_type.rb'
-
'
app/graphql/types/user_state_enum.rb'
-
'
ee/app/graphql/ee/mutations/alert_management/http_integration/create.rb'
-
'
ee/app/graphql/ee/mutations/alert_management/http_integration/update.rb'
-
'
ee/app/graphql/ee/mutations/boards/issues/issue_move_list.rb'
-
'
ee/app/graphql/ee/mutations/issues/create.rb'
-
'
ee/app/graphql/ee/mutations/issues/update.rb'
-
'
ee/app/graphql/ee/types/alert_management/http_integration_type.rb'
-
'
ee/app/graphql/ee/types/board_list_type.rb'
-
'
ee/app/graphql/ee/types/board_type.rb'
-
'
ee/app/graphql/ee/types/group_type.rb'
-
'
ee/app/graphql/ee/types/project_type.rb'
-
'
ee/app/graphql/ee/types/query_type.rb'
-
'
ee/app/graphql/mutations/app_sec/fuzzing/api/ci_configuration/create.rb'
-
'
ee/app/graphql/mutations/boards/epic_boards/create.rb'
-
'
ee/app/graphql/mutations/boards/epic_boards/epic_move_list.rb'
...
...
GITALY_SERVER_VERSION
View file @
e9900469
d924490032231edb9452acdaca7d8e4747cf6ab4
50eff62c1b1f5730c7ca18597493b0b2926e72ca
app/assets/javascripts/boards/components/board_add_new_column.vue
View file @
e9900469
...
...
@@ -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
);
}
this
.
createList
({
labelId
:
this
.
selectedId
});
},
filterItems
(
searchTerm
)
{
...
...
app/assets/javascripts/boards/components/board_card_layout_deprecated.vue
View file @
e9900469
...
...
@@ -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
});
}
this
.
setActiveId
({
id
:
this
.
issue
.
id
,
sidebarType
:
ISSUABLE
});
},
},
};
...
...
app/assets/javascripts/boards/components/board_content.vue
View file @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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
);
return
this
.
boardLists
[
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
.
track
(
'
click_button
'
,
{
label
:
'
remove_list
'
});
this
.
removeList
(
this
.
activeId
);
this
.
unsetActiveId
();
}
},
...
...
app/assets/javascripts/boards/filtered_search_boards.js
View file @
e9900469
...
...
@@ -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
();
}
updateHistory
({
url
:
`?
${
path
.
substr
(
1
)}${
groupByParam
?
`&group_by=
${
groupByParam
}
`
:
''
}
`
,
});
vuexstore
.
dispatch
(
'
performSearch
'
);
}
removeTokens
()
{
...
...
app/assets/javascripts/boards/index.js
View file @
e9900469
...
...
@@ -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
);
}
boardsStore
.
create
();
// 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 @
e9900469
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,16 +47,8 @@ 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
,
{
return
createElement
(
BoardsSelector
,
{
props
:
this
.
boardsSelectorProps
,
});
},
...
...
app/assets/javascripts/boards/stores/actions.js
View file @
e9900469
...
...
@@ -82,11 +82,8 @@ export default {
'
setFilters
'
,
convertObjectPropsToCamelCase
(
queryToObject
(
window
.
location
.
search
,
{
gatherArrays
:
true
})),
);
if
(
gon
.
features
.
graphqlBoardLists
)
{
dispatch
(
'
fetchLists
'
);
dispatch
(
'
resetIssues
'
);
}
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 @
e9900469
...
...
@@ -51,8 +51,4 @@ export default {
isEpicBoard
:
()
=>
{
return
false
;
},
shouldUseGraphQL
:
()
=>
{
return
gon
?.
features
?.
graphqlBoardLists
;
},
};
app/controllers/groups/boards_controller.rb
View file @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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/graphql/types/repository/blob_type.rb
View file @
e9900469
...
...
@@ -48,10 +48,10 @@ module Types
description:
'Size (in bytes) of the blob, or the blob target if stored externally.'
field
:raw_blob
,
GraphQL
::
Types
::
String
,
null:
true
,
method: :data
,
description:
'
The r
aw content of the blob.'
description:
'
R
aw content of the blob.'
field
:raw_text_blob
,
GraphQL
::
Types
::
String
,
null:
true
,
method: :text_only_data
,
description:
'
The r
aw content of the blob, if the blob is text data.'
description:
'
R
aw content of the blob, if the blob is text data.'
field
:stored_externally
,
GraphQL
::
Types
::
Boolean
,
null:
true
,
method: :stored_externally?
,
description:
"Whether the blob's content is stored externally (for instance, in LFS)."
...
...
@@ -69,7 +69,7 @@ module Types
description:
'Web path to replace the blob content.'
field
:file_type
,
GraphQL
::
Types
::
String
,
null:
true
,
description:
'
The e
xpected format of the blob based on the extension.'
description:
'
E
xpected format of the blob based on the extension.'
field
:simple_viewer
,
type:
Types
::
BlobViewerType
,
description:
'Blob content simple viewer.'
,
...
...
app/graphql/types/root_storage_statistics_type.rb
View file @
e9900469
...
...
@@ -6,14 +6,14 @@ module Types
authorize
:read_statistics
field
:storage_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'T
he t
otal storage in bytes.'
field
:repository_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The
Git repository size in bytes.'
field
:lfs_objects_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The
LFS objects size in bytes.'
field
:build_artifacts_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The
CI artifacts size in bytes.'
field
:packages_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The p
ackages size in bytes.'
field
:wiki_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The w
iki size in bytes.'
field
:snippets_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The s
nippets size in bytes.'
field
:pipeline_artifacts_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The
CI pipeline artifacts size in bytes.'
field
:uploads_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
The u
ploads size in bytes.'
field
:storage_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'Total storage in bytes.'
field
:repository_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'Git repository size in bytes.'
field
:lfs_objects_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'LFS objects size in bytes.'
field
:build_artifacts_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'CI artifacts size in bytes.'
field
:packages_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
P
ackages size in bytes.'
field
:wiki_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
W
iki size in bytes.'
field
:snippets_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
S
nippets size in bytes.'
field
:pipeline_artifacts_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'CI pipeline artifacts size in bytes.'
field
:uploads_size
,
GraphQL
::
FLOAT_TYPE
,
null:
false
,
description:
'
U
ploads size in bytes.'
end
end
app/graphql/types/snippet_type.rb
View file @
e9900469
...
...
@@ -22,7 +22,7 @@ module Types
null:
false
field
:project
,
Types
::
ProjectType
,
description:
'
The p
roject the snippet is associated with.'
,
description:
'
P
roject the snippet is associated with.'
,
null:
true
,
authorize: :read_project
...
...
@@ -30,7 +30,7 @@ module Types
# when the admin setting restricted visibility
# level is set to public
field
:author
,
Types
::
UserType
,
description:
'
The o
wner of the snippet.'
,
description:
'
O
wner of the snippet.'
,
null:
true
field
:file_name
,
GraphQL
::
Types
::
String
,
...
...
app/graphql/types/snippets/blob_type.rb
View file @
e9900469
...
...
@@ -17,7 +17,7 @@ module Types
null:
true
field
:raw_plain_data
,
GraphQL
::
Types
::
String
,
description:
'
The r
aw content of the blob, if the blob is text data.'
,
description:
'
R
aw content of the blob, if the blob is text data.'
,
null:
true
field
:raw_path
,
GraphQL
::
Types
::
String
,
...
...
app/graphql/types/snippets/visibility_scopes_enum.rb
View file @
e9900469
...
...
@@ -3,9 +3,9 @@
module
Types
module
Snippets
class
VisibilityScopesEnum
<
BaseEnum
value
'private'
,
description:
'
The s
nippet is visible only to the snippet creator.'
,
value:
'are_private'
value
'internal'
,
description:
'
The s
nippet is visible for any logged in user except external users.'
,
value:
'are_internal'
value
'public'
,
description:
'
The s
nippet can be accessed without any authentication.'
,
value:
'are_public'
value
'private'
,
description:
'
S
nippet is visible only to the snippet creator.'
,
value:
'are_private'
value
'internal'
,
description:
'
S
nippet is visible for any logged in user except external users.'
,
value:
'are_internal'
value
'public'
,
description:
'
S
nippet can be accessed without any authentication.'
,
value:
'are_public'
end
end
end
app/graphql/types/terraform/state_type.rb
View file @
e9900469
...
...
@@ -19,7 +19,7 @@ module Types
field
:locked_by_user
,
Types
::
UserType
,
null:
true
,
description:
'
The u
ser currently holding a lock on the Terraform state.'
description:
'
U
ser currently holding a lock on the Terraform state.'
field
:locked_at
,
Types
::
TimeType
,
null:
true
,
...
...
@@ -28,7 +28,7 @@ module Types
field
:latest_version
,
Types
::
Terraform
::
StateVersionType
,
complexity:
3
,
null:
true
,
description:
'
The l
atest version of the Terraform state.'
description:
'
L
atest version of the Terraform state.'
field
:created_at
,
Types
::
TimeType
,
null:
false
,
...
...
app/graphql/types/terraform/state_version_type.rb
View file @
e9900469
...
...
@@ -15,7 +15,7 @@ module Types
field
:created_by_user
,
Types
::
UserType
,
null:
true
,
description:
'
The u
ser that created this version.'
description:
'
U
ser that created this version.'
field
:download_path
,
GraphQL
::
Types
::
String
,
null:
true
,
...
...
@@ -23,7 +23,7 @@ module Types
field
:job
,
Types
::
Ci
::
JobType
,
null:
true
,
description:
'
The j
ob that created this version.'
description:
'
J
ob that created this version.'
field
:serial
,
GraphQL
::
Types
::
Int
,
null:
true
,
...
...
app/graphql/types/timelog_type.rb
View file @
e9900469
...
...
@@ -14,31 +14,31 @@ module Types
field
:time_spent
,
GraphQL
::
Types
::
Int
,
null:
false
,
description:
'T
he t
ime spent displayed in seconds.'
description:
'Time spent displayed in seconds.'
field
:user
,
Types
::
UserType
,
null:
false
,
description:
'
The u
ser that logged the time.'
description:
'
U
ser that logged the time.'
field
:issue
,
Types
::
IssueType
,
null:
true
,
description:
'
The i
ssue that logged time was added to.'
description:
'
I
ssue that logged time was added to.'
field
:merge_request
,
Types
::
MergeRequestType
,
null:
true
,
description:
'
The m
erge request that logged time was added to.'
description:
'
M
erge request that logged time was added to.'
field
:note
,
Types
::
Notes
::
NoteType
,
null:
true
,
description:
'
The note where the quick action to add the logged time was executed
.'
description:
'
Note where the quick action was executed to add the logged time
.'
field
:summary
,
GraphQL
::
Types
::
String
,
null:
true
,
description:
'
The s
ummary of how the time was spent.'
description:
'
S
ummary of how the time was spent.'
def
user
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
User
,
object
.
user_id
).
find
...
...
app/graphql/types/todo_state_enum.rb
View file @
e9900469
...
...
@@ -2,7 +2,7 @@
module
Types
class
TodoStateEnum
<
BaseEnum
value
'pending'
,
description:
"
The s
tate of the todo is pending."
value
'done'
,
description:
"
The s
tate of the todo is done."
value
'pending'
,
description:
"
S
tate of the todo is pending."
value
'done'
,
description:
"
S
tate of the todo is done."
end
end
app/graphql/types/todo_target_enum.rb
View file @
e9900469
...
...
@@ -2,11 +2,11 @@
module
Types
class
TodoTargetEnum
<
BaseEnum
value
'COMMIT'
,
value:
'Commit'
,
description:
'
A
Commit.'
value
'ISSUE'
,
value:
'Issue'
,
description:
'
An
Issue.'
value
'MERGEREQUEST'
,
value:
'MergeRequest'
,
description:
'
A MergeR
equest.'
value
'DESIGN'
,
value:
'DesignManagement::Design'
,
description:
'
A
Design.'
value
'ALERT'
,
value:
'AlertManagement::Alert'
,
description:
'A
n A
lert.'
value
'COMMIT'
,
value:
'Commit'
,
description:
'Commit.'
value
'ISSUE'
,
value:
'Issue'
,
description:
'Issue.'
value
'MERGEREQUEST'
,
value:
'MergeRequest'
,
description:
'
Merge r
equest.'
value
'DESIGN'
,
value:
'DesignManagement::Design'
,
description:
'Design.'
value
'ALERT'
,
value:
'AlertManagement::Alert'
,
description:
'Alert.'
end
end
...
...
app/graphql/types/todo_type.rb
View file @
e9900469
...
...
@@ -14,7 +14,7 @@ module Types
null:
false
field
:project
,
Types
::
ProjectType
,
description:
'
The p
roject this to-do item is associated with.'
,
description:
'
P
roject this to-do item is associated with.'
,
null:
true
,
authorize: :read_project
...
...
@@ -24,7 +24,7 @@ module Types
authorize: :read_group
field
:author
,
Types
::
UserType
,
description:
'
The a
uthor of this to-do item.'
,
description:
'
A
uthor of this to-do item.'
,
null:
false
field
:action
,
Types
::
TodoActionEnum
,
...
...
app/graphql/types/user_interface.rb
View file @
e9900469
...
...
@@ -72,7 +72,7 @@ module Types
field
:location
,
type:
::
GraphQL
::
Types
::
String
,
null:
true
,
description:
'
The l
ocation of the user.'
description:
'
L
ocation of the user.'
field
:project_memberships
,
type:
Types
::
ProjectMemberType
.
connection_type
,
null:
true
,
...
...
app/graphql/types/user_merge_request_interaction_type.rb
View file @
e9900469
...
...
@@ -28,7 +28,7 @@ module Types
field
:review_state
,
::
Types
::
MergeRequestReviewStateEnum
,
null:
true
,
description:
'
The s
tate of the review by this user.'
description:
'
S
tate of the review by this user.'
field
:reviewed
,
type:
::
GraphQL
::
Types
::
Boolean
,
...
...
app/graphql/types/user_state_enum.rb
View file @
e9900469
...
...
@@ -5,8 +5,8 @@ module Types
graphql_name
'UserState'
description
'Possible states of a user'
value
'active'
,
'
The u
ser is active and is able to use the system.'
,
value:
'active'
value
'blocked'
,
'
The u
ser has been blocked and is prevented from using the system.'
,
value:
'blocked'
value
'deactivated'
,
'
The u
ser is no longer active and is unable to use the system.'
,
value:
'deactivated'
value
'active'
,
'
U
ser is active and is able to use the system.'
,
value:
'active'
value
'blocked'
,
'
U
ser has been blocked and is prevented from using the system.'
,
value:
'blocked'
value
'deactivated'
,
'
U
ser is no longer active and is unable to use the system.'
,
value:
'deactivated'
end
end
app/views/shared/boards/_show.html.haml
View file @
e9900469
-
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 @
7f3527b1
%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 @
7f3527b1
---
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/api/graphql/reference/index.md
View file @
e9900469
This diff is collapsed.
Click to expand it.
doc/user/project/issue_board.md
View file @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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
),
);
const
key
=
`
${
this
.
columnType
}
Id`
;
return
this
.
getListByTypeId
({
[
key
]:
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
);
}
// eslint-disable-next-line @gitlab/require-i18n-strings
this
.
createList
({
[
`
${
this
.
columnType
}
Id`
]:
this
.
selectedId
});
},
filterItems
(
searchTerm
)
{
...
...
ee/app/assets/javascripts/boards/components/board_settings_wip_limit.vue
View file @
e9900469
<
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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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
'
);
}
dispatch
(
'
fetchLists
'
);
dispatch
(
'
resetIssues
'
);
},
fetchEpicsSwimlanes
({
state
,
commit
},
{
fetchNext
=
false
}
=
{})
{
...
...
@@ -221,38 +215,30 @@ export default {
commit
(
types
.
SET_SHOW_LABELS
,
val
);
},
updateListWipLimit
({
commit
,
getters
,
dispatch
},
{
maxIssueCount
,
listId
})
{
if
(
getters
.
shouldUseGraphQL
)
{
return
gqlClient
.
mutate
({
mutation
:
listUpdateLimitMetricsMutation
,
variables
:
{
input
:
{
listId
,
maxIssueCount
,
},
updateListWipLimit
({
commit
,
dispatch
},
{
maxIssueCount
,
listId
})
{
return
gqlClient
.
mutate
({
mutation
:
listUpdateLimitMetricsMutation
,
variables
:
{
input
:
{
listId
,
maxIssueCount
,
},
})
.
then
(({
data
})
=>
{
if
(
data
?.
boardListUpdateLimitMetrics
?.
errors
.
length
)
{
throw
new
Error
();
}
},
})
.
then
(({
data
})
=>
{
if
(
data
?.
boardListUpdateLimitMetrics
?.
errors
.
length
)
{
throw
new
Error
();
}
commit
(
types
.
UPDATE_LIST_SUCCESS
,
{
listId
,
list
:
data
.
boardListUpdateLimitMetrics
?.
list
,
});
})
.
catch
(()
=>
{
dispatch
(
'
handleUpdateListFailure
'
);
commit
(
types
.
UPDATE_LIST_SUCCESS
,
{
listId
,
list
:
data
.
boardListUpdateLimitMetrics
?.
list
,
});
}
return
axios
.
put
(
`
${
boardsStoreEE
.
store
.
state
.
endpoints
.
listsEndpoint
}
/
${
listId
}
`
,
{
list
:
{
max_issue_count
:
maxIssueCount
,
},
});
})
.
catch
(()
=>
{
dispatch
(
'
handleUpdateListFailure
'
);
});
},
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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -54,8 +54,4 @@ export default {
isEpicBoard
:
(
state
)
=>
{
return
state
.
issuableType
===
issuableTypes
.
epic
;
},
shouldUseGraphQL
:
(
state
)
=>
{
return
state
.
isShowingEpicsSwimlanes
||
gon
?.
features
?.
graphqlBoardLists
;
},
};
ee/app/graphql/ee/mutations/alert_management/http_integration/create.rb
View file @
e9900469
...
...
@@ -10,11 +10,11 @@ module EE
prepended
do
argument
:payload_example
,
::
Types
::
JsonStringType
,
required:
false
,
description:
'
The e
xample of an alert payload.'
description:
'
E
xample of an alert payload.'
argument
:payload_attribute_mappings
,
[
::
Types
::
AlertManagement
::
PayloadAlertFieldInputType
],
required:
false
,
description:
'
The custom mapping of GitLab alert attributes to fields from the payload_
example.'
description:
'
Custom mapping of GitLab alert attributes to fields from the payload
example.'
end
end
end
...
...
ee/app/graphql/ee/mutations/alert_management/http_integration/update.rb
View file @
e9900469
...
...
@@ -10,11 +10,11 @@ module EE
prepended
do
argument
:payload_example
,
::
Types
::
JsonStringType
,
required:
false
,
description:
'
The e
xample of an alert payload.'
description:
'
E
xample of an alert payload.'
argument
:payload_attribute_mappings
,
[
::
Types
::
AlertManagement
::
PayloadAlertFieldInputType
],
required:
false
,
description:
'
The custom mapping of GitLab alert attributes to fields from the payload_
example.'
description:
'
Custom mapping of GitLab alert attributes to fields from the payload
example.'
end
end
end
...
...
ee/app/graphql/ee/mutations/issues/create.rb
View file @
e9900469
...
...
@@ -12,7 +12,7 @@ module EE
argument
:epic_id
,
::
Types
::
GlobalIDType
[
::
Epic
],
required:
false
,
description:
'
The
ID of an epic to associate the issue with.'
description:
'ID of an epic to associate the issue with.'
end
override
:resolve
...
...
ee/app/graphql/ee/mutations/issues/update.rb
View file @
e9900469
...
...
@@ -12,7 +12,7 @@ module EE
argument
:epic_id
,
::
Types
::
GlobalIDType
[
::
Epic
],
required:
false
,
loads:
::
Types
::
EpicType
,
description:
'
The
ID of the parent epic. NULL when removing the association.'
description:
'ID of the parent epic. NULL when removing the association.'
end
def
resolve
(
**
args
)
...
...
ee/app/graphql/ee/types/alert_management/http_integration_type.rb
View file @
e9900469
...
...
@@ -9,7 +9,7 @@ module EE
prepended
do
field
:payload_example
,
::
Types
::
JsonStringType
,
null:
true
,
description:
'
The e
xample of an alert payload.'
description:
'
E
xample of an alert payload.'
field
:payload_attribute_mappings
,
[
::
Types
::
AlertManagement
::
PayloadAlertMappingFieldType
],
null:
true
,
...
...
ee/app/graphql/ee/types/board_list_type.rb
View file @
e9900469
...
...
@@ -17,7 +17,7 @@ module EE
field
:assignee
,
::
Types
::
UserType
,
null:
true
,
description:
'Assignee in the list.'
field
:limit_metric
,
::
EE
::
Types
::
ListLimitMetricEnum
,
null:
true
,
description:
'
The c
urrent limit metric for the list.'
description:
'
C
urrent limit metric for the list.'
field
:total_weight
,
GraphQL
::
Types
::
Int
,
null:
true
,
description:
'Total weight of all issues in the list.'
...
...
ee/app/graphql/ee/types/board_type.rb
View file @
e9900469
...
...
@@ -7,7 +7,7 @@ module EE
prepended
do
field
:assignee
,
type:
::
Types
::
UserType
,
null:
true
,
description:
'
The b
oard assignee.'
description:
'
B
oard assignee.'
field
:epics
,
::
Types
::
Boards
::
BoardEpicType
.
connection_type
,
null:
true
,
description:
'Epics associated with board issues.'
,
...
...
@@ -18,10 +18,10 @@ module EE
description:
'Labels of the board.'
field
:milestone
,
type:
::
Types
::
MilestoneType
,
null:
true
,
description:
'
The b
oard milestone.'
description:
'
B
oard milestone.'
field
:iteration
,
type:
::
Types
::
IterationType
,
null:
true
,
description:
'
The b
oard iteration.'
description:
'
B
oard iteration.'
field
:weight
,
type:
GraphQL
::
Types
::
Int
,
null:
true
,
description:
'Weight of the board.'
...
...
ee/app/graphql/ee/types/group_type.rb
View file @
e9900469
...
...
@@ -84,13 +84,13 @@ module EE
field
:billable_members_count
,
::
GraphQL
::
Types
::
Int
,
null:
true
,
description:
'
The n
umber of billable users in the group.'
description:
'
N
umber of billable users in the group.'
field
:dora
,
::
Types
::
DoraType
,
null:
true
,
method: :itself
,
description:
"
The g
roup's DORA metrics."
description:
"
G
roup's DORA metrics."
end
end
end
...
...
ee/app/graphql/ee/types/project_type.rb
View file @
e9900469
...
...
@@ -87,7 +87,7 @@ module EE
field
:dast_scanner_profiles
,
::
Types
::
DastScannerProfileType
.
connection_type
,
null:
true
,
description:
'
The
DAST scanner profiles associated with the project.'
description:
'DAST scanner profiles associated with the project.'
field
:dast_site_validations
,
::
Types
::
DastSiteValidationType
.
connection_type
,
...
...
@@ -165,7 +165,7 @@ module EE
field
:push_rules
,
::
Types
::
PushRulesType
,
null:
true
,
description:
"
The p
roject's push rules settings."
,
description:
"
P
roject's push rules settings."
,
method: :push_rule
field
:path_locks
,
...
...
@@ -192,7 +192,7 @@ module EE
::
Types
::
DoraType
,
null:
true
,
method: :itself
,
description:
"
The p
roject's DORA metrics."
description:
"
P
roject's DORA metrics."
end
def
api_fuzzing_ci_configuration
...
...
ee/app/graphql/ee/types/query_type.rb
View file @
e9900469
...
...
@@ -26,7 +26,7 @@ module EE
description:
"Find a vulnerability."
do
argument
:id
,
::
Types
::
GlobalIDType
[
::
Vulnerability
],
required:
true
,
description:
'
The
Global ID of the Vulnerability.'
description:
'Global ID of the Vulnerability.'
end
field
:vulnerabilities_count_by_day
,
...
...
@@ -64,7 +64,7 @@ module EE
field
:ci_minutes_usage
,
::
Types
::
Ci
::
Minutes
::
NamespaceMonthlyUsageType
.
connection_type
,
null:
true
,
description:
'
The m
onthly CI minutes usage data for the current user.'
description:
'
M
onthly CI minutes usage data for the current user.'
end
def
vulnerability
(
id
:)
...
...
ee/spec/features/boards/group_boards/multiple_boards_spec.rb
View file @
e9900469
...
...
@@ -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 @
7f3527b1
# 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 @
7f3527b1
This diff is collapsed.
Click to expand it.
ee/spec/features/boards/user_adds_lists_to_board_spec.rb
View file @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
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 @
e9900469
...
...
@@ -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 @
e9900469
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 @
e9900469
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
'
,
()
=>
{
const
spy
=
jest
.
fn
().
mockResolvedValue
({
data
:
{
boardListUpdateLimitMetrics
:
{
list
:
{
maxIssueCount
:
0
}
}
},
});
beforeEach
(()
=>
{
addList
(
4
);
const
spy
=
jest
.
fn
().
mockResolvedValue
({
config
:
{
data
:
JSON
.
stringify
({
list
:
{
max_issue_count
:
0
}
})
},
});
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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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,63 +46,41 @@ 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
'
,
()
=>
{
describe
(
'
can admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
});
gon
.
features
=
{
graphqlBoardLists
:
true
,
};
createComponent
({
canAdminList
:
true
});
});
describe
(
'
can admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
,
canAdminList
:
true
});
});
it
(
'
renders draggable component
'
,
()
=>
{
expect
(
wrapper
.
find
(
Draggable
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
can not admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
true
,
canAdminList
:
false
});
});
it
(
'
does not render draggable component
'
,
()
=>
{
expect
(
wrapper
.
find
(
Draggable
).
exists
()).
toBe
(
false
);
});
it
(
'
renders draggable component
'
,
()
=>
{
expect
(
wrapper
.
find
(
Draggable
).
exists
()).
toBe
(
true
);
});
});
describe
(
'
graphqlBoardLists feature flag disabled
'
,
()
=>
{
describe
(
'
can not admin list
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
graphqlBoardListsEnabled
:
false
});
createComponent
({
canAdminList
:
false
});
});
it
(
'
does not render draggable component
'
,
()
=>
{
...
...
spec/frontend/boards/components/board_filtered_search_spec.js
View file @
e9900469
...
...
@@ -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 @
e9900469
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
'
,
()
=>
{
createComponent
({
list
:
mockLabelList
,
activeId
:
listId
});
expect
(
findLabel
().
props
(
'
backgroundColor
'
)).
toBe
(
labelColor
);
});
});
describe
(
'
when activeId is not in boardsStore
'
,
()
=>
{
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
boardsStore
.
addList
({
id
:
listId
,
label
:
{
title
:
labelTitle
,
color
:
labelColor
}
});
store
.
state
.
activeId
=
inactiveId
;
createComponent
();
});
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 @
e9900469
...
...
@@ -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 @
e9900469
...
...
@@ -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