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
266f5084
Commit
266f5084
authored
Apr 08, 2022
by
Florie Guibert
Committed by
Peter Hegman
Apr 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Search board by Any and Current iteration cadence
Behind iteration_cadences feature flag
parent
197edba5
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
340 additions
and
38 deletions
+340
-38
app/assets/javascripts/boards/components/board_filtered_search.vue
...s/javascripts/boards/components/board_filtered_search.vue
+26
-4
ee/app/assets/javascripts/boards/boards_util.js
ee/app/assets/javascripts/boards/boards_util.js
+3
-1
ee/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
...scripts/boards/components/issue_board_filtered_search.vue
+2
-1
ee/app/assets/javascripts/boards/stores/actions.js
ee/app/assets/javascripts/boards/stores/actions.js
+36
-0
ee/app/assets/javascripts/boards/stores/mutation_types.js
ee/app/assets/javascripts/boards/stores/mutation_types.js
+4
-0
ee/app/assets/javascripts/boards/stores/mutations.js
ee/app/assets/javascripts/boards/stores/mutations.js
+14
-0
ee/app/assets/javascripts/issues/list/components/issues_list_app.vue
...ts/javascripts/issues/list/components/issues_list_app.vue
+1
-0
ee/app/assets/javascripts/issues/list/queries/search_iteration_cadences.query.graphql
...sues/list/queries/search_iteration_cadences.query.graphql
+25
-0
ee/app/assets/javascripts/iterations/utils.js
ee/app/assets/javascripts/iterations/utils.js
+2
-2
ee/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
...ts/vue_shared/components/filtered_search_bar/constants.js
+5
-3
ee/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue
...components/filtered_search_bar/tokens/iteration_token.vue
+72
-21
ee/spec/features/boards/board_filters_spec.rb
ee/spec/features/boards/board_filters_spec.rb
+3
-3
ee/spec/frontend/boards/components/issue_board_filtered_search_spec.js
...end/boards/components/issue_board_filtered_search_spec.js
+1
-0
ee/spec/frontend/boards/mock_data.js
ee/spec/frontend/boards/mock_data.js
+19
-1
ee/spec/frontend/boards/stores/actions_spec.js
ee/spec/frontend/boards/stores/actions_spec.js
+103
-0
ee/spec/frontend/iterations/mock_data.js
ee/spec/frontend/iterations/mock_data.js
+4
-0
ee/spec/frontend/iterations/utils_spec.js
ee/spec/frontend/iterations/utils_spec.js
+2
-0
ee/spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js
...onents/filtered_search_bar/tokens/iteration_token_spec.js
+13
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/frontend/boards/components/board_filtered_search_spec.js
.../frontend/boards/components/board_filtered_search_spec.js
+2
-2
No files found.
app/assets/javascripts/boards/components/board_filtered_search.vue
View file @
266f5084
...
...
@@ -4,7 +4,10 @@ import { mapActions } from 'vuex';
import
{
getIdFromGraphQLId
,
isGid
}
from
'
~/graphql_shared/utils
'
;
import
{
updateHistory
,
setUrlParams
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
FILTERED_SEARCH_TERM
}
from
'
~/vue_shared/components/filtered_search_bar/constants
'
;
import
{
FILTERED_SEARCH_TERM
,
FILTER_ANY
,
}
from
'
~/vue_shared/components/filtered_search_bar/constants
'
;
import
FilteredSearch
from
'
~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
'
;
import
{
AssigneeFilterType
}
from
'
~/boards/constants
'
;
...
...
@@ -42,6 +45,7 @@ export default {
search
,
milestoneTitle
,
iterationId
,
iterationCadenceId
,
types
,
weight
,
epicId
,
...
...
@@ -95,10 +99,20 @@ export default {
});
}
if
(
iterationId
)
{
let
iterationData
=
null
;
if
(
iterationId
&&
iterationCadenceId
)
{
iterationData
=
`
${
iterationId
}
&
${
iterationCadenceId
}
`
;
}
else
if
(
iterationCadenceId
)
{
iterationData
=
`
${
FILTER_ANY
}
&
${
iterationCadenceId
}
`
;
}
else
if
(
iterationId
)
{
iterationData
=
iterationId
;
}
if
(
iterationData
)
{
filteredSearchValue
.
push
({
type
:
'
iteration
'
,
value
:
{
data
:
iteration
Id
,
operator
:
'
=
'
},
value
:
{
data
:
iteration
Data
,
operator
:
'
=
'
},
});
}
...
...
@@ -228,9 +242,12 @@ export default {
epicId
,
myReactionEmoji
,
iterationId
,
iterationCadenceId
,
releaseTag
,
confidential
,
}
=
this
.
filterParams
;
let
iteration
=
iterationId
;
let
cadence
=
iterationCadenceId
;
let
notParams
=
{};
if
(
Object
.
prototype
.
hasOwnProperty
.
call
(
this
.
filterParams
,
'
not
'
))
{
...
...
@@ -251,6 +268,10 @@ export default {
);
}
if
(
iterationId
?.
includes
(
'
&
'
))
{
[
iteration
,
cadence
]
=
iterationId
.
split
(
'
&
'
);
}
return
mapValues
(
{
...
notParams
,
...
...
@@ -259,7 +280,8 @@ export default {
assignee_username
:
assigneeUsername
,
assignee_id
:
assigneeId
,
milestone_title
:
milestoneTitle
,
iteration_id
:
iterationId
,
iteration_id
:
iteration
,
iteration_cadence_id
:
cadence
,
search
,
types
,
weight
,
...
...
ee/app/assets/javascripts/boards/boards_util.js
View file @
266f5084
...
...
@@ -5,6 +5,7 @@ import {
import
{
TYPE_EPIC_BOARD
,
TYPE_ITERATION
,
TYPE_ITERATIONS_CADENCE
,
TYPE_EPIC
,
TYPE_MILESTONE
,
TYPE_USER
,
...
...
@@ -66,7 +67,7 @@ function fullIterationCadenceId(id) {
return
null
;
}
return
`gid://gitlab/Iterations::Cadence/
${
getIdFromGraphQLId
(
id
)}
`
;
return
convertToGraphQLId
(
TYPE_ITERATIONS_CADENCE
,
getIdFromGraphQLId
(
id
))
;
}
export
function
fullUserId
(
userId
)
{
...
...
@@ -266,6 +267,7 @@ export const FiltersInfo = {
},
iterationCadenceId
:
{
negatedSupport
:
false
,
transform
:
(
iterationCadenceId
)
=>
fullIterationCadenceId
(
iterationCadenceId
),
},
weight
:
{
negatedSupport
:
true
,
...
...
ee/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
View file @
266f5084
...
...
@@ -62,6 +62,7 @@ export default {
token
:
IterationToken
,
unique
:
true
,
fetchIterations
:
this
.
fetchIterations
,
fetchIterationCadences
:
this
.
fetchIterationCadences
,
},
]
:
[]),
...
...
@@ -78,7 +79,7 @@ export default {
},
},
methods
:
{
...
mapActions
([
'
fetchIterations
'
]),
...
mapActions
([
'
fetchIterations
'
,
'
fetchIterationCadences
'
]),
},
};
</
script
>
ee/app/assets/javascripts/boards/stores/actions.js
View file @
266f5084
...
...
@@ -17,6 +17,7 @@ import { historyPushState, convertObjectPropsToCamelCase } from '~/lib/utils/com
import
{
mergeUrlParams
,
removeParams
,
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
import
searchIterationQuery
from
'
ee/issues/list/queries/search_iterations.query.graphql
'
;
import
searchIterationCadencesQuery
from
'
ee/issues/list/queries/search_iteration_cadences.query.graphql
'
;
import
{
fullEpicBoardId
,
formatEpic
,
...
...
@@ -193,6 +194,41 @@ export default {
});
},
fetchIterationCadences
({
state
,
commit
},
title
)
{
commit
(
types
.
RECEIVE_CADENCES_REQUEST
);
const
{
fullPath
,
boardType
}
=
state
;
const
id
=
Number
(
title
);
let
variables
=
{
fullPath
,
title
,
isProject
:
boardType
===
BoardType
.
project
};
if
(
!
Number
.
isNaN
(
id
)
&&
title
!==
''
)
{
variables
=
{
fullPath
,
id
,
isProject
:
boardType
===
BoardType
.
project
};
}
return
gqlClient
.
query
({
query
:
searchIterationCadencesQuery
,
variables
,
})
.
then
(({
data
})
=>
{
const
errors
=
data
[
boardType
]?.
errors
;
const
cadences
=
data
[
boardType
]?.
iterationCadences
?.
nodes
;
if
(
errors
?.[
0
])
{
throw
new
Error
(
errors
[
0
]);
}
commit
(
types
.
RECEIVE_CADENCES_SUCCESS
,
cadences
);
return
cadences
;
})
.
catch
((
e
)
=>
{
commit
(
types
.
RECEIVE_CADENCES_FAILURE
);
throw
e
;
});
},
performSearch
({
dispatch
,
getters
})
{
dispatch
(
'
setFilters
'
,
...
...
ee/app/assets/javascripts/boards/stores/mutation_types.js
View file @
266f5084
...
...
@@ -26,3 +26,7 @@ export const SET_SELECTED_GROUP = 'SET_SELECTED_GROUP';
export
const
RECEIVE_ITERATIONS_REQUEST
=
'
RECEIVE_ITERATIONS_REQUEST
'
;
export
const
RECEIVE_ITERATIONS_SUCCESS
=
'
RECEIVE_ITERATIONS_SUCCESS
'
;
export
const
RECEIVE_ITERATIONS_FAILURE
=
'
RECEIVE_ITERATIONS_FAILURE
'
;
export
const
RECEIVE_CADENCES_REQUEST
=
'
RECEIVE_CADENCES_REQUEST
'
;
export
const
RECEIVE_CADENCES_SUCCESS
=
'
RECEIVE_CADENCES_SUCCESS
'
;
export
const
RECEIVE_CADENCES_FAILURE
=
'
RECEIVE_CADENCES_FAILURE
'
;
ee/app/assets/javascripts/boards/stores/mutations.js
View file @
266f5084
...
...
@@ -119,6 +119,20 @@ export default {
state
.
error
=
__
(
'
Failed to load iterations.
'
);
},
[
mutationTypes
.
RECEIVE_CADENCES_REQUEST
](
state
)
{
state
.
iterationCadencesLoading
=
true
;
},
[
mutationTypes
.
RECEIVE_CADENCES_SUCCESS
](
state
,
cadences
)
{
state
.
iterationCadences
=
cadences
;
state
.
iterationCadencesLoading
=
false
;
},
[
mutationTypes
.
RECEIVE_CADENCES_FAILURE
](
state
)
{
state
.
iterationCadencesLoading
=
false
;
state
.
error
=
__
(
'
Failed to load iteration cadences.
'
);
},
[
mutationTypes
.
REQUEST_MORE_EPICS
]:
(
state
)
=>
{
Vue
.
set
(
state
,
'
epicsSwimlanesFetchInProgress
'
,
{
...
state
.
epicsSwimlanesFetchInProgress
,
...
...
ee/app/assets/javascripts/issues/list/components/issues_list_app.vue
View file @
266f5084
...
...
@@ -38,6 +38,7 @@ export default {
token
:
IterationToken
,
fetchIterations
:
this
.
fetchIterations
,
recentSuggestionsStorageKey
:
`
${
this
.
fullPath
}
-issues-recent-tokens-iteration`
,
hideDefaultCadenceOptions
:
true
,
});
}
...
...
ee/app/assets/javascripts/issues/list/queries/search_iteration_cadences.query.graphql
0 → 100644
View file @
266f5084
query
searchIterationCadences
(
$fullPath
:
ID
!
$title
:
String
$id
:
ID
$isProject
:
Boolean
=
false
)
{
group
(
fullPath
:
$fullPath
)
@skip
(
if
:
$isProject
)
{
id
iterationCadences
(
title
:
$title
,
id
:
$id
,
includeAncestorGroups
:
true
)
{
nodes
{
id
title
}
}
}
project
(
fullPath
:
$fullPath
)
@include
(
if
:
$isProject
)
{
id
iterationCadences
(
title
:
$title
,
id
:
$id
,
includeAncestorGroups
:
true
)
{
nodes
{
id
title
}
}
}
}
ee/app/assets/javascripts/iterations/utils.js
View file @
266f5084
...
...
@@ -25,7 +25,7 @@ export function groupByIterationCadences(iterations) {
if
(
!
iteration
.
iterationCadence
)
{
return
;
}
const
{
title
}
=
iteration
.
iterationCadence
;
const
{
title
,
id
}
=
iteration
.
iterationCadence
;
const
cadenceIteration
=
{
id
:
iteration
.
id
,
title
:
iteration
.
title
,
...
...
@@ -35,7 +35,7 @@ export function groupByIterationCadences(iterations) {
if
(
cadence
)
{
cadence
.
iterations
.
push
(
cadenceIteration
);
}
else
{
cadences
.
push
({
title
,
iterations
:
[
cadenceIteration
]
});
cadences
.
push
({
title
,
iterations
:
[
cadenceIteration
]
,
id
});
}
});
return
cadences
;
...
...
ee/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
View file @
266f5084
import
{
__
}
from
'
~/locale
'
;
import
{
DEFAULT_LABEL_ANY
,
DEFAULT_NONE_ANY
,
FILTER_CURRENT
,
}
from
'
~/vue_shared/components/filtered_search_bar/constants
'
;
...
...
@@ -8,9 +9,10 @@ export * from '~/vue_shared/components/filtered_search_bar/constants';
export
const
WEIGHT_TOKEN_SUGGESTIONS_SIZE
=
21
;
export
const
DEFAULT_ITERATIONS
=
DEFAULT_NONE_ANY
.
concat
([
{
value
:
FILTER_CURRENT
,
text
:
__
(
'
Current
'
)
},
]);
export
const
DEFAULT_CURRENT
=
{
value
:
FILTER_CURRENT
,
text
:
__
(
'
Current
'
)
};
export
const
DEFAULT_ITERATIONS
=
DEFAULT_NONE_ANY
.
concat
(
DEFAULT_CURRENT
);
export
const
DEFAULT_CADENCES
=
[
DEFAULT_LABEL_ANY
,
DEFAULT_CURRENT
];
export
const
TOKEN_TITLE_ITERATION
=
__
(
'
Iteration
'
);
export
const
TOKEN_TITLE_EPIC
=
__
(
'
Epic
'
);
...
...
ee/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue
View file @
266f5084
...
...
@@ -2,12 +2,13 @@
import
{
GlDropdownDivider
,
GlDropdownSectionHeader
,
GlFilteredSearchSuggestion
}
from
'
@gitlab/ui
'
;
import
{
groupByIterationCadences
,
getIterationPeriod
}
from
'
ee/iterations/utils
'
;
import
createFlash
from
'
~/flash
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
TYPE_ITERATIONS_CADENCE
}
from
'
~/graphql_shared/constants
'
;
import
{
convertToGraphQLId
,
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
OPERATOR_IS
}
from
'
~/vue_shared/components/filtered_search_bar/constants
'
;
import
BaseToken
from
'
~/vue_shared/components/filtered_search_bar/tokens/base_token.vue
'
;
import
glFeatureFlagMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
IterationTitle
from
'
ee/iterations/components/iteration_title.vue
'
;
import
{
DEFAULT_ITERATIONS
}
from
'
../constants
'
;
import
{
DEFAULT_
CADENCES
,
DEFAULT_
ITERATIONS
}
from
'
../constants
'
;
export
default
{
components
:
{
...
...
@@ -17,7 +18,6 @@ export default {
GlFilteredSearchSuggestion
,
IterationTitle
,
},
mixins
:
[
glFeatureFlagMixin
()],
props
:
{
active
:
{
type
:
Boolean
,
...
...
@@ -42,9 +42,23 @@ export default {
defaultIterations
()
{
return
this
.
config
.
defaultIterations
||
DEFAULT_ITERATIONS
;
},
defaultCadenceOptions
()
{
return
!
this
.
config
.
hideDefaultCadenceOptions
&&
this
.
value
.
operator
===
OPERATOR_IS
?
DEFAULT_CADENCES
:
[];
},
},
methods
:
{
getActiveIteration
(
iterations
,
data
)
{
if
(
data
?.
includes
(
'
&
'
))
{
const
iterationCadenceId
=
this
.
getIterationCadenceId
(
data
);
const
iteration
=
iterations
.
find
(
(
i
)
=>
i
?.
iterationCadence
?.
id
===
convertToGraphQLId
(
TYPE_ITERATIONS_CADENCE
,
iterationCadenceId
),
);
return
iteration
?.
iterationCadence
;
}
return
iterations
.
find
((
iteration
)
=>
this
.
getId
(
iteration
)
===
data
);
},
groupIterationsByCadence
(
iterations
)
{
...
...
@@ -52,25 +66,55 @@ export default {
},
fetchIterations
(
searchTerm
)
{
this
.
loading
=
true
;
this
.
config
.
fetchIterations
(
searchTerm
)
.
then
((
response
)
=>
{
this
.
iterations
=
Array
.
isArray
(
response
)
?
response
:
response
.
data
;
})
.
catch
(()
=>
{
createFlash
({
message
:
__
(
'
There was a problem fetching iterations.
'
)
});
})
.
finally
(()
=>
{
this
.
loading
=
false
;
});
if
(
searchTerm
?.
includes
(
'
&
'
))
{
this
.
config
.
fetchIterationCadences
(
this
.
getIterationCadenceId
(
searchTerm
))
.
then
((
response
)
=>
{
this
.
iterations
=
[
{
iterationCadence
:
response
[
0
],
},
];
})
.
catch
((
error
)
=>
{
createFlash
({
message
:
this
.
$options
.
i18n
.
errorMessage
,
captureError
:
true
,
error
});
})
.
finally
(()
=>
{
this
.
loading
=
false
;
});
}
else
{
this
.
config
.
fetchIterations
(
searchTerm
)
.
then
((
response
)
=>
{
this
.
iterations
=
Array
.
isArray
(
response
)
?
response
:
response
.
data
;
})
.
catch
(()
=>
{
createFlash
({
message
:
this
.
$options
.
i18n
.
errorMessage
});
})
.
finally
(()
=>
{
this
.
loading
=
false
;
});
}
},
getId
(
option
)
{
return
getIdFromGraphQLId
(
option
.
id
).
toString
();
},
getI
d
(
iteration
)
{
return
getIdFromGraphQLId
(
iteration
.
id
).
toString
()
;
getI
terationCadenceId
(
input
)
{
return
input
.
split
(
'
&
'
)[
1
]
;
},
iterationTokenText
(
iteration
)
{
const
cadenceTitle
=
iteration
.
iterationCadence
.
title
;
return
`
${
cadenceTitle
}
${
getIterationPeriod
(
iteration
)}
`
;
getIterationOption
(
input
)
{
return
input
.
split
(
'
&
'
)[
0
];
},
iterationTokenText
(
iterationOrCadence
,
inputValue
)
{
if
(
iterationOrCadence
?.
id
?.
includes
(
TYPE_ITERATIONS_CADENCE
))
{
return
`
${
this
.
getIterationOption
(
inputValue
)}
::
${
iterationOrCadence
.
title
}
`
;
}
const
cadenceTitle
=
iterationOrCadence
.
iterationCadence
.
title
;
return
`
${
cadenceTitle
}
${
getIterationPeriod
(
iterationOrCadence
)}
`
;
},
},
i18n
:
{
errorMessage
:
__
(
'
There was a problem fetching iterations.
'
),
},
};
</
script
>
...
...
@@ -88,7 +132,7 @@ export default {
v-on=
"$listeners"
>
<template
#view
="
{ viewTokenProps: { inputValue, activeTokenValue } }">
{{
activeTokenValue
?
iterationTokenText
(
activeTokenValue
)
:
inputValue
}}
{{
activeTokenValue
?
iterationTokenText
(
activeTokenValue
,
inputValue
)
:
inputValue
}}
</
template
>
<
template
#suggestions-list=
"{ suggestions }"
>
<template
v-for=
"(cadence, index) in groupIterationsByCadence(suggestions)"
>
...
...
@@ -100,6 +144,13 @@ export default {
>
{{
cadence
.
title
}}
</gl-dropdown-section-header>
<gl-filtered-search-suggestion
v-for=
"option in defaultCadenceOptions"
:key=
"`$
{option.value}-${index}`"
:value="`${option.value}
&
${getId(cadence)}`"
>
{{
option
.
text
}}
</gl-filtered-search-suggestion>
<gl-filtered-search-suggestion
v-for=
"iteration in cadence.iterations"
:key=
"iteration.id"
...
...
ee/spec/features/boards/board_filters_spec.rb
View file @
266f5084
...
...
@@ -54,9 +54,9 @@ RSpec.describe 'Issue board filters', :js do
it
'loads all the iterations when opened and submit one as filter'
,
:aggregate_failures
do
expect
(
find
(
'.board:nth-child(1)'
)).
to
have_selector
(
'.board-card'
,
count:
2
)
#
4
dropdown items must be shown
# None, Any, Current
and iteration
expect_filtered_search_dropdown_results
(
filter_dropdown
,
4
)
#
6
dropdown items must be shown
# None, Any, Current
, iteration, Any and Current within cadence
expect_filtered_search_dropdown_results
(
filter_dropdown
,
6
)
click_on
iteration
.
period
filter_submit
.
click
...
...
ee/spec/frontend/boards/components/issue_board_filtered_search_spec.js
View file @
266f5084
...
...
@@ -54,6 +54,7 @@ describe('IssueBoardFilter', () => {
fetchAuthorsSpy
,
wrapper
.
vm
.
fetchMilestones
,
wrapper
.
vm
.
fetchIterations
,
wrapper
.
vm
.
fetchIterationCadences
,
);
expect
(
wrapper
.
findComponent
(
BoardFilteredSearch
).
props
(
'
tokens
'
)).
toEqual
(
...
...
ee/spec/frontend/boards/mock_data.js
View file @
266f5084
...
...
@@ -180,6 +180,17 @@ export const mockIterationsResponse = {
},
};
export
const
mockIterationCadences
=
[
{
id
:
'
gid://gitlab/Iterations::Cadence/11
'
,
title
:
'
Cadence 1
'
,
},
{
id
:
'
gid://gitlab/Iterations::Cadence/22
'
,
title
:
'
Cadence 2
'
,
},
];
export
const
labels
=
[
{
id
:
'
gid://gitlab/GroupLabel/5
'
,
...
...
@@ -446,7 +457,13 @@ export const mockGroup2 = {
export
const
mockSubGroups
=
[
mockGroup0
,
mockGroup1
,
mockGroup2
];
export
const
mockTokens
=
(
fetchLabels
,
fetchAuthors
,
fetchMilestones
,
fetchIterations
)
=>
[
export
const
mockTokens
=
(
fetchLabels
,
fetchAuthors
,
fetchMilestones
,
fetchIterations
,
fetchIterationCadences
,
)
=>
[
{
icon
:
'
user
'
,
title
:
__
(
'
Assignee
'
),
...
...
@@ -556,6 +573,7 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, fetchIter
],
unique
:
true
,
fetchIterations
,
fetchIterationCadences
,
token
:
IterationToken
,
},
{
...
...
ee/spec/frontend/boards/stores/actions_spec.js
View file @
266f5084
...
...
@@ -10,6 +10,7 @@ import {
IterationIDs
,
}
from
'
ee/boards/constants
'
;
import
epicCreateMutation
from
'
ee/boards/graphql/epic_create.mutation.graphql
'
;
import
searchIterationCadencesQuery
from
'
ee/issues/list/queries/search_iteration_cadences.query.graphql
'
;
import
actions
,
{
gqlClient
}
from
'
ee/boards/stores/actions
'
;
import
*
as
types
from
'
ee/boards/stores/mutation_types
'
;
import
mutations
from
'
ee/boards/stores/mutations
'
;
...
...
@@ -25,6 +26,7 @@ import * as typesCE from '~/boards/stores/mutation_types';
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
import
{
mergeUrlParams
,
removeParams
}
from
'
~/lib/utils/url_utility
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
labels
,
mockLists
,
...
...
@@ -35,6 +37,7 @@ import {
mockAssignees
,
mockSubGroups
,
mockGroup0
,
mockIterationCadences
,
}
from
'
../mock_data
'
;
Vue
.
use
(
Vuex
);
...
...
@@ -1163,6 +1166,106 @@ describe('fetchIterations', () => {
});
});
describe
(
'
fetchIterationCadences
'
,
()
=>
{
const
queryResponse
=
{
data
:
{
group
:
{
iterationCadences
:
{
nodes
:
mockIterationCadences
,
},
},
},
};
const
queryErrors
=
{
data
:
{
group
:
{
errors
:
[
'
You cannot view these iteration cadences
'
],
iterationCadences
:
{},
},
},
};
function
createStore
({
state
=
{
boardType
:
'
group
'
,
fullPath
:
'
gitlab-org/gitlab
'
,
iterationCadences
:
[],
iterationCadencesLoading
:
false
,
},
}
=
{})
{
return
new
Vuex
.
Store
({
state
,
mutations
,
});
}
it
(
'
sets iterationCadencesLoading to true
'
,
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
store
=
createStore
();
actions
.
fetchIterationCadences
(
store
);
expect
(
store
.
state
.
iterationCadencesLoading
).
toBe
(
true
);
});
describe
(
'
success
'
,
()
=>
{
it
(
'
with search by title - sets state.iterationCadences from query result
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
store
=
createStore
();
await
actions
.
fetchIterationCadences
(
store
,
'
search
'
);
expect
(
store
.
state
.
iterationCadencesLoading
).
toBe
(
false
);
expect
(
store
.
state
.
iterationCadences
).
toBe
(
mockIterationCadences
);
expect
(
gqlClient
.
query
).
toHaveBeenCalledWith
({
query
:
searchIterationCadencesQuery
,
variables
:
{
fullPath
:
'
gitlab-org/gitlab
'
,
title
:
'
search
'
,
isProject
:
false
,
},
});
});
it
(
'
with search by id - sets state.iterationCadences from query result
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
const
store
=
createStore
();
await
actions
.
fetchIterationCadences
(
store
,
'
11
'
);
expect
(
store
.
state
.
iterationCadencesLoading
).
toBe
(
false
);
expect
(
store
.
state
.
iterationCadences
).
toBe
(
mockIterationCadences
);
expect
(
gqlClient
.
query
).
toHaveBeenCalledWith
({
query
:
searchIterationCadencesQuery
,
variables
:
{
fullPath
:
'
gitlab-org/gitlab
'
,
id
:
11
,
isProject
:
false
,
},
});
});
});
describe
(
'
failure
'
,
()
=>
{
it
(
'
throws an error and displays an error message
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryErrors
);
const
store
=
createStore
();
await
expect
(
actions
.
fetchIterationCadences
(
store
)).
rejects
.
toThrow
();
expect
(
store
.
state
.
iterationCadencesLoading
).
toBe
(
false
);
expect
(
store
.
state
.
error
).
toBe
(
__
(
'
Failed to load iteration cadences.
'
));
});
});
});
describe
(
'
fetchAssignees
'
,
()
=>
{
const
queryResponse
=
{
data
:
{
...
...
ee/spec/frontend/iterations/mock_data.js
View file @
266f5084
...
...
@@ -224,6 +224,7 @@ export const mockIterationsWithCadences = [
startDate
:
'
2021-11-23T12:34:56
'
,
dueDate
:
'
2021-11-30T12:34:56
'
,
iterationCadence
:
{
id
:
1
,
title
:
'
cadence 1
'
,
},
},
...
...
@@ -233,6 +234,7 @@ export const mockIterationsWithCadences = [
startDate
:
'
2021-11-23T12:34:56
'
,
dueDate
:
'
2021-11-30T12:34:56
'
,
iterationCadence
:
{
id
:
2
,
title
:
'
cadence 2
'
,
},
},
...
...
@@ -242,6 +244,7 @@ export const mockIterationsWithCadences = [
startDate
:
'
2021-11-23T12:34:56
'
,
dueDate
:
'
2021-11-30T12:34:56
'
,
iterationCadence
:
{
id
:
2
,
title
:
'
cadence 2
'
,
},
},
...
...
@@ -251,6 +254,7 @@ export const mockIterationsWithCadences = [
startDate
:
'
2021-11-23T12:34:56
'
,
dueDate
:
'
2021-11-30T12:34:56
'
,
iterationCadence
:
{
id
:
1
,
title
:
'
cadence 1
'
,
},
},
...
...
ee/spec/frontend/iterations/utils_spec.js
View file @
266f5084
...
...
@@ -15,6 +15,7 @@ describe('groupByIterationCadences', () => {
const
period
=
'
Nov 23, 2021 - Nov 30, 2021
'
;
const
expected
=
[
{
id
:
1
,
title
:
'
cadence 1
'
,
iterations
:
[
{
id
:
1
,
title
:
'
iteration 1
'
,
period
},
...
...
@@ -22,6 +23,7 @@ describe('groupByIterationCadences', () => {
],
},
{
id
:
2
,
title
:
'
cadence 2
'
,
iterations
:
[
{
id
:
2
,
title
:
'
iteration 2
'
,
period
},
...
...
ee/spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js
View file @
266f5084
...
...
@@ -73,6 +73,19 @@ describe('IterationToken', () => {
expect
(
fetchIterationsSpy
).
toHaveBeenCalledWith
(
search
);
});
it
(
'
fetches iteration cadences when cadence is set
'
,
()
=>
{
const
search
=
'
Current&1
'
;
const
fetchIterationCadencesSpy
=
jest
.
fn
().
mockResolvedValue
();
wrapper
=
createComponent
({
config
:
{
...
mockIterationToken
,
fetchIterationCadences
:
fetchIterationCadencesSpy
},
});
wrapper
.
findComponent
(
GlFilteredSearchToken
).
vm
.
$emit
(
'
input
'
,
{
data
:
search
});
expect
(
fetchIterationCadencesSpy
).
toHaveBeenCalledWith
(
'
1
'
);
});
it
(
'
renders error message when request fails
'
,
async
()
=>
{
const
fetchIterationsSpy
=
jest
.
fn
().
mockRejectedValue
();
...
...
locale/gitlab.pot
View file @
266f5084
...
...
@@ -15451,6 +15451,9 @@ msgstr ""
msgid "Failed to load groups, users and deploy keys."
msgstr ""
msgid "Failed to load iteration cadences."
msgstr ""
msgid "Failed to load iterations."
msgstr ""
...
...
spec/frontend/boards/components/board_filtered_search_spec.js
View file @
266f5084
...
...
@@ -124,7 +124,7 @@ describe('BoardFilteredSearch', () => {
{
type
:
'
milestone
'
,
value
:
{
data
:
'
New Milestone
'
,
operator
:
'
=
'
}
},
{
type
:
'
type
'
,
value
:
{
data
:
'
INCIDENT
'
,
operator
:
'
=
'
}
},
{
type
:
'
weight
'
,
value
:
{
data
:
'
2
'
,
operator
:
'
=
'
}
},
{
type
:
'
iteration
'
,
value
:
{
data
:
'
3341
'
,
operator
:
'
=
'
}
},
{
type
:
'
iteration
'
,
value
:
{
data
:
'
Any&3
'
,
operator
:
'
=
'
}
},
{
type
:
'
release
'
,
value
:
{
data
:
'
v1.0.0
'
,
operator
:
'
=
'
}
},
];
jest
.
spyOn
(
urlUtility
,
'
updateHistory
'
);
...
...
@@ -134,7 +134,7 @@ describe('BoardFilteredSearch', () => {
title
:
''
,
replace
:
true
,
url
:
'
http://test.host/?author_username=root&label_name[]=label&label_name[]=label%262&assignee_username=root&milestone_title=New%20Milestone&iteration_id=
3341
&types=INCIDENT&weight=2&release_tag=v1.0.0
'
,
'
http://test.host/?author_username=root&label_name[]=label&label_name[]=label%262&assignee_username=root&milestone_title=New%20Milestone&iteration_id=
Any&iteration_cadence_id=3
&types=INCIDENT&weight=2&release_tag=v1.0.0
'
,
});
});
...
...
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