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
2d8bb4a1
Commit
2d8bb4a1
authored
Dec 02, 2021
by
Simon Knox
Committed by
Natalia Tepluhina
Dec 02, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add iteration to issues created on scoped boards
parent
30cfc3c3
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
394 additions
and
13 deletions
+394
-13
app/assets/javascripts/boards/stores/actions.js
app/assets/javascripts/boards/stores/actions.js
+8
-8
ee/app/assets/javascripts/boards/boards_util.js
ee/app/assets/javascripts/boards/boards_util.js
+68
-1
ee/app/assets/javascripts/boards/graphql/board_current_iteration.query.graphql
...ipts/boards/graphql/board_current_iteration.query.graphql
+25
-0
ee/app/assets/javascripts/boards/graphql/issue.fragment.graphql
.../assets/javascripts/boards/graphql/issue.fragment.graphql
+8
-0
ee/app/assets/javascripts/boards/stores/actions.js
ee/app/assets/javascripts/boards/stores/actions.js
+42
-1
ee/spec/features/boards/scoped_issue_board_spec.rb
ee/spec/features/boards/scoped_issue_board_spec.rb
+24
-1
ee/spec/frontend/boards/boards_util_spec.js
ee/spec/frontend/boards/boards_util_spec.js
+67
-0
ee/spec/frontend/boards/stores/actions_spec.js
ee/spec/frontend/boards/stores/actions_spec.js
+151
-1
spec/frontend/boards/stores/actions_spec.js
spec/frontend/boards/stores/actions_spec.js
+1
-1
No files found.
app/assets/javascripts/boards/stores/actions.js
View file @
2d8bb4a1
...
...
@@ -16,24 +16,24 @@ import {
ListTypeTitles
,
DraggableItemTypes
,
}
from
'
ee_else_ce/boards/constants
'
;
import
createBoardListMutation
from
'
ee_else_ce/boards/graphql/board_list_create.mutation.graphql
'
;
import
issueMoveListMutation
from
'
ee_else_ce/boards/graphql/issue_move_list.mutation.graphql
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
formatIssueInput
,
formatBoardLists
,
formatListIssues
,
formatListsPageInfo
,
formatIssue
,
formatIssueInput
,
updateListPosition
,
moveItemListHelper
,
getMoveData
,
FiltersInfo
,
filterVariables
,
}
from
'
../boards_util
'
;
}
from
'
ee_else_ce/boards/boards_util
'
;
import
createBoardListMutation
from
'
ee_else_ce/boards/graphql/board_list_create.mutation.graphql
'
;
import
issueMoveListMutation
from
'
ee_else_ce/boards/graphql/issue_move_list.mutation.graphql
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
gqlClient
}
from
'
../graphql
'
;
import
boardLabelsQuery
from
'
../graphql/board_labels.query.graphql
'
;
import
groupBoardMilestonesQuery
from
'
../graphql/group_board_milestones.query.graphql
'
;
...
...
ee/app/assets/javascripts/boards/boards_util.js
View file @
2d8bb4a1
import
{
FiltersInfo
as
FiltersInfoCE
}
from
'
~/boards/boards_util
'
;
import
{
FiltersInfo
as
FiltersInfoCE
,
formatIssueInput
as
formatIssueInputCe
,
}
from
'
~/boards/boards_util
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
objectToQuery
,
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
import
{
EPIC_LANE_BASE_HEIGHT
,
...
...
@@ -11,6 +15,17 @@ import {
EpicFilterType
,
}
from
'
./constants
'
;
export
{
formatBoardLists
,
formatListIssues
,
formatListsPageInfo
,
formatIssue
,
updateListPosition
,
moveItemListHelper
,
getMoveData
,
filterVariables
,
}
from
'
~/boards/boards_util
'
;
export
function
getMilestone
({
milestone
})
{
return
milestone
||
null
;
}
...
...
@@ -23,6 +38,30 @@ export function fullMilestoneId(milestoneId) {
return
`gid://gitlab/Milestone/
${
milestoneId
}
`
;
}
function
fullIterationId
(
id
)
{
if
(
!
id
)
{
return
null
;
}
if
(
id
===
IterationIDs
.
CURRENT
)
{
return
'
CURRENT
'
;
}
if
(
id
===
IterationIDs
.
UPCOMING
)
{
return
'
UPCOMING
'
;
}
return
`gid://gitlab/Iteration/
${
id
}
`
;
}
function
fullIterationCadenceId
(
id
)
{
if
(
!
id
)
{
return
null
;
}
return
`gid://gitlab/Iterations::Cadence/
${
getIdFromGraphQLId
(
id
)}
`
;
}
export
function
fullUserId
(
userId
)
{
return
`gid://gitlab/User/
${
userId
}
`
;
}
...
...
@@ -96,6 +135,34 @@ export function formatEpicInput(epicInput, boardConfig) {
};
}
function
iterationObj
(
iterationId
)
{
const
isWildcard
=
Object
.
values
(
IterationIDs
).
includes
(
iterationId
);
const
key
=
isWildcard
?
'
iterationWildcardId
'
:
'
iterationId
'
;
return
{
[
key
]:
fullIterationId
(
iterationId
),
};
}
export
function
formatIssueInput
(
issueInput
,
boardConfig
)
{
const
{
iterationId
,
iterationCadenceId
}
=
boardConfig
;
const
iteration
=
gon
.
features
?.
iterationCadences
?
{
iterationCadenceId
:
fullIterationCadenceId
(
iterationCadenceId
),
...
iterationObj
(
iterationId
),
}
:
{
iterationCadenceId
,
...
iterationObj
(
iterationId
),
};
return
{
...
formatIssueInputCe
(
issueInput
,
boardConfig
),
...
iteration
,
};
}
export
function
transformBoardConfig
(
boardConfig
)
{
const
updatedBoardConfig
=
{};
const
passedFilterParams
=
queryToObject
(
window
.
location
.
search
,
{
gatherArrays
:
true
});
...
...
ee/app/assets/javascripts/boards/graphql/board_current_iteration.query.graphql
0 → 100644
View file @
2d8bb4a1
query
BoardCurrentIteration
(
$fullPath
:
ID
!,
$isGroup
:
Boolean
=
true
)
{
group
(
fullPath
:
$fullPath
)
@include
(
if
:
$isGroup
)
{
id
iterations
(
state
:
current
,
first
:
1
,
includeAncestors
:
true
)
{
nodes
{
id
iterationCadence
{
id
}
}
}
}
project
(
fullPath
:
$fullPath
)
@skip
(
if
:
$isGroup
)
{
id
iterations
(
state
:
current
,
first
:
1
,
includeAncestors
:
true
)
{
nodes
{
id
iterationCadence
{
id
}
}
}
}
}
ee/app/assets/javascripts/boards/graphql/issue.fragment.graphql
View file @
2d8bb4a1
...
...
@@ -29,6 +29,14 @@ fragment IssueNode on Issue {
milestone
{
...
MilestoneFragment
}
iteration
{
id
title
iterationCadence
{
id
title
}
}
labels
{
nodes
{
id
...
...
ee/app/assets/javascripts/boards/stores/actions.js
View file @
2d8bb4a1
...
...
@@ -27,7 +27,7 @@ import {
FiltersInfo
,
}
from
'
../boards_util
'
;
import
{
EpicFilterType
,
GroupByParamType
,
FilterFields
}
from
'
../constants
'
;
import
{
EpicFilterType
,
GroupByParamType
,
FilterFields
,
IterationIDs
}
from
'
../constants
'
;
import
createEpicBoardListMutation
from
'
../graphql/epic_board_list_create.mutation.graphql
'
;
import
epicCreateMutation
from
'
../graphql/epic_create.mutation.graphql
'
;
import
epicMoveListMutation
from
'
../graphql/epic_move_list.mutation.graphql
'
;
...
...
@@ -35,6 +35,7 @@ import epicsSwimlanesQuery from '../graphql/epics_swimlanes.query.graphql';
import
listUpdateLimitMetricsMutation
from
'
../graphql/list_update_limit_metrics.mutation.graphql
'
;
import
listsEpicsQuery
from
'
../graphql/lists_epics.query.graphql
'
;
import
subGroupsQuery
from
'
../graphql/sub_groups.query.graphql
'
;
import
currentIterationQuery
from
'
../graphql/board_current_iteration.query.graphql
'
;
import
updateBoardEpicUserPreferencesMutation
from
'
../graphql/update_board_epic_user_preferences.mutation.graphql
'
;
import
*
as
types
from
'
./mutation_types
'
;
...
...
@@ -94,6 +95,46 @@ export { gqlClient };
export
default
{
...
actionsCE
,
addListNewIssue
:
async
(
{
state
:
{
boardConfig
,
boardType
,
fullPath
},
dispatch
,
commit
},
issueInputObj
,
)
=>
{
const
{
iterationId
}
=
boardConfig
;
let
{
iterationCadenceId
}
=
boardConfig
;
if
(
!
iterationCadenceId
&&
iterationId
===
IterationIDs
.
CURRENT
)
{
const
iteration
=
await
gqlClient
.
query
({
query
:
currentIterationQuery
,
context
:
{
isSingleRequest
:
true
,
},
variables
:
{
isGroup
:
boardType
===
BoardType
.
group
,
fullPath
,
},
})
.
then
(({
data
})
=>
{
return
data
[
boardType
]?.
iterations
?.
nodes
?.[
0
];
});
iterationCadenceId
=
iteration
.
iterationCadence
.
id
;
}
return
actionsCE
.
addListNewIssue
(
{
state
:
{
boardConfig
:
{
...
boardConfig
,
iterationId
,
iterationCadenceId
},
boardType
,
fullPath
,
},
dispatch
,
commit
,
},
issueInputObj
,
);
},
setFilters
:
({
commit
,
dispatch
,
state
:
{
issuableType
}
},
filters
)
=>
{
if
(
filters
.
groupBy
===
GroupByParamType
.
epic
)
{
dispatch
(
'
setEpicSwimlanes
'
);
...
...
ee/spec/features/boards/scoped_issue_board_spec.rb
View file @
2d8bb4a1
...
...
@@ -278,7 +278,7 @@ RSpec.describe 'Scoped issue boards', :js do
context
'iteration'
do
context
'group with iterations'
do
let_it_be
(
:cadence
)
{
create
(
:iterations_cadence
,
group:
group
)
}
let_it_be
(
:iteration
)
{
create
(
:
iteration
,
group:
group
,
iterations_cadence:
cadence
)
}
let_it_be
(
:iteration
)
{
create
(
:
current_iteration
,
:skip_future_date_validation
,
iterations_cadence:
cadence
,
group:
group
,
start_date:
1
.
day
.
ago
,
due_date:
Date
.
today
)
}
context
'board not scoped to iteration'
do
it
'sets board to current iteration'
do
...
...
@@ -293,6 +293,29 @@ RSpec.describe 'Scoped issue boards', :js do
end
context
'board scoped to current iteration'
do
before
do
stub_feature_flags
(
iteration_cadences:
false
)
end
it
'adds current iteration to new issues'
do
update_board_scope
(
'current_iteration'
,
true
)
wait_for_requests
page
.
within
(
first
(
'.board'
))
do
click_button
'New issue'
end
page
.
within
(
first
(
'.board-new-issue-form'
))
do
find
(
'.form-control'
).
set
(
'issue in current iteration'
)
click_button
'Create issue'
end
wait_for_requests
expect
(
find
(
'[data-testid="issue-boards-sidebar"]'
)).
to
have_text
(
iteration
.
title
)
end
it
'removes current iteration from board'
do
create_board_scope
(
'current_iteration'
,
true
)
...
...
ee/spec/frontend/boards/boards_util_spec.js
View file @
2d8bb4a1
...
...
@@ -3,7 +3,9 @@ import {
formatListEpics
,
formatEpicListsPageInfo
,
transformBoardConfig
,
formatIssueInput
,
}
from
'
ee/boards/boards_util
'
;
import
{
IterationIDs
}
from
'
ee/boards/constants
'
;
import
setWindowLocation
from
'
helpers/set_window_location_helper
'
;
import
{
mockLabel
}
from
'
./mock_data
'
;
...
...
@@ -105,6 +107,71 @@ describe('formatEpicListsPageInfo', () => {
});
});
describe
(
'
formatIssueInput
'
,
()
=>
{
const
issueInput
=
{
labelIds
:
[
'
gid://gitlab/GroupLabel/5
'
],
projectPath
:
'
gitlab-org/gitlab-test
'
,
id
:
'
gid://gitlab/Issue/11
'
,
};
const
expected
=
{
projectPath
:
'
gitlab-org/gitlab-test
'
,
id
:
'
gid://gitlab/Issue/11
'
,
labelIds
:
[
'
gid://gitlab/GroupLabel/5
'
],
assigneeIds
:
[],
milestoneId
:
undefined
,
};
it
(
'
adds iterationIds to input
'
,
()
=>
{
const
boardConfig
=
{
iterationId
:
66
,
};
const
result
=
formatIssueInput
(
issueInput
,
boardConfig
);
expect
(
result
).
toEqual
({
...
expected
,
iterationId
:
'
gid://gitlab/Iteration/66
'
,
});
});
it
(
'
adds iterationWildcardId to when current iteration selected
'
,
()
=>
{
const
boardConfig
=
{
iterationId
:
IterationIDs
.
CURRENT
,
};
const
result
=
formatIssueInput
(
issueInput
,
boardConfig
);
expect
(
result
).
toEqual
({
...
expected
,
iterationWildcardId
:
'
CURRENT
'
,
iterationCadenceId
:
undefined
,
});
});
it
(
'
includes iterationCadenceId and iterationId
'
,
()
=>
{
gon
.
features
=
{
...
gon
.
features
,
iterationCadences
:
true
,
};
const
boardConfig
=
{
iterationId
:
66
,
iterationCadenceId
:
11
,
};
const
result
=
formatIssueInput
(
issueInput
,
boardConfig
);
expect
(
result
).
toEqual
({
...
expected
,
iterationCadenceId
:
'
gid://gitlab/Iterations::Cadence/11
'
,
iterationId
:
'
gid://gitlab/Iteration/66
'
,
});
delete
gon
.
features
.
iterationCadences
;
});
});
describe
(
'
transformBoardConfig
'
,
()
=>
{
const
boardConfig
=
{
milestoneTitle
:
'
milestone
'
,
...
...
ee/spec/frontend/boards/stores/actions_spec.js
View file @
2d8bb4a1
...
...
@@ -2,7 +2,13 @@ import axios from 'axios';
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Vue
from
'
vue
'
;
import
Vuex
from
'
vuex
'
;
import
{
BoardType
,
GroupByParamType
,
listsQuery
,
issuableTypes
}
from
'
ee/boards/constants
'
;
import
{
BoardType
,
GroupByParamType
,
listsQuery
,
issuableTypes
,
IterationIDs
,
}
from
'
ee/boards/constants
'
;
import
epicCreateMutation
from
'
ee/boards/graphql/epic_create.mutation.graphql
'
;
import
actions
,
{
gqlClient
}
from
'
ee/boards/stores/actions
'
;
import
*
as
types
from
'
ee/boards/stores/mutation_types
'
;
...
...
@@ -12,7 +18,9 @@ import { TEST_HOST } from 'helpers/test_constants';
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
{
mockMoveIssueParams
,
mockMoveData
,
mockMoveState
}
from
'
jest/boards/mock_data
'
;
import
{
formatListIssues
}
from
'
~/boards/boards_util
'
;
import
{
formatIssueInput
}
from
'
ee_else_ce/boards/boards_util
'
;
import
listsIssuesQuery
from
'
~/boards/graphql/lists_issues.query.graphql
'
;
import
issueCreateMutation
from
'
~/boards/graphql/issue_create.mutation.graphql
'
;
import
*
as
typesCE
from
'
~/boards/stores/mutation_types
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
*
as
commonUtils
from
'
~/lib/utils/common_utils
'
;
...
...
@@ -1390,3 +1398,145 @@ describe('setActiveEpicLabels', () => {
);
});
});
describe
(
'
addListNewIssue
'
,
()
=>
{
let
state
;
const
iterationCadenceId
=
'
gid://gitlab/Iterations::Cadence/1
'
;
const
baseState
=
{
boardType
:
'
group
'
,
fullPath
:
'
gitlab-org/gitlab
'
,
boardConfig
:
{
labelIds
:
[],
},
};
const
queryResponse
=
{
data
:
{
group
:
{
id
:
'
gid://gitlab/Group/1
'
,
iterations
:
{
nodes
:
[
{
id
:
'
gid://gitlab/Iteration/1
'
,
iterationCadence
:
{
id
:
iterationCadenceId
,
},
},
],
},
},
},
};
const
fakeList
=
{};
beforeEach
(()
=>
{
jest
.
spyOn
(
gqlClient
,
'
query
'
).
mockResolvedValue
(
queryResponse
);
});
describe
(
'
without cadenceId
'
,
()
=>
{
describe
(
'
currentIteration selected in board config
'
,
()
=>
{
beforeEach
(()
=>
{
state
=
{
...
baseState
,
boardConfig
:
{
iterationId
:
IterationIDs
.
CURRENT
,
},
};
});
it
(
'
adds iterationCadenceId from iteration
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
createIssue
:
{
errors
:
[],
},
},
});
await
actions
.
addListNewIssue
(
{
dispatch
:
jest
.
fn
(),
commit
:
jest
.
fn
(),
state
},
{
issueInput
:
mockIssue
,
list
:
fakeList
},
);
expect
(
gqlClient
.
mutate
).
toHaveBeenCalledWith
({
mutation
:
issueCreateMutation
,
variables
:
{
input
:
formatIssueInput
(
mockIssue
,
{
...
state
.
boardConfig
,
iterationCadenceId
,
}),
},
});
});
});
describe
(
'
currentIteration not in boardConfig
'
,
()
=>
{
beforeEach
(()
=>
{
state
=
{
...
baseState
,
boardConfig
:
{
iterationId
:
null
,
},
};
});
it
(
'
does not add iterationCadenceId
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
createIssue
:
{
errors
:
[],
},
},
});
await
actions
.
addListNewIssue
(
{
dispatch
:
jest
.
fn
(),
commit
:
jest
.
fn
(),
state
},
{
issueInput
:
mockIssue
,
list
:
fakeList
},
);
expect
(
gqlClient
.
mutate
).
toHaveBeenCalledWith
({
mutation
:
issueCreateMutation
,
variables
:
{
input
:
formatIssueInput
(
mockIssue
,
state
.
boardConfig
),
},
});
});
});
});
describe
(
'
with iterationCadenceId
'
,
()
=>
{
beforeEach
(()
=>
{
state
=
{
...
baseState
,
boardConfig
:
{
iterationId
:
IterationIDs
.
CURRENT
,
iterationCadenceId
,
},
};
});
it
(
'
does not make query for cadence of current iteration
'
,
async
()
=>
{
jest
.
spyOn
(
gqlClient
,
'
mutate
'
).
mockResolvedValue
({
data
:
{
createIssue
:
{
errors
:
[],
},
},
});
await
actions
.
addListNewIssue
(
{
dispatch
:
jest
.
fn
(),
commit
:
jest
.
fn
(),
state
},
{
issueInput
:
mockIssue
,
list
:
fakeList
},
);
expect
(
gqlClient
.
query
).
not
.
toHaveBeenCalled
();
expect
(
gqlClient
.
mutate
).
toHaveBeenCalledWith
({
mutation
:
issueCreateMutation
,
variables
:
{
input
:
formatIssueInput
(
mockIssue
,
state
.
boardConfig
),
},
});
});
});
});
spec/frontend/boards/stores/actions_spec.js
View file @
2d8bb4a1
...
...
@@ -20,7 +20,7 @@ import {
formatIssue
,
getMoveData
,
updateListPosition
,
}
from
'
~
/boards/boards_util
'
;
}
from
'
ee_else_ce
/boards/boards_util
'
;
import
{
gqlClient
}
from
'
~/boards/graphql
'
;
import
destroyBoardListMutation
from
'
~/boards/graphql/board_list_destroy.mutation.graphql
'
;
import
issueCreateMutation
from
'
~/boards/graphql/issue_create.mutation.graphql
'
;
...
...
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