Support creating board lists with status values
What does this MR do and why?
As part of the configurable work item statuses initiative, this MR adds support to create board lists with system-defined or custom status values.
Changes
- Added
system_defined_status_idandcustom_status_idcolumns toliststable with appropriate indexes and foreign keys - Updated the GraphQL
boardListCreatemutation to support status-based lists - Added validation logic to ensure:
- Only one status type (system-defined or custom) can be used per list
- No duplicate status lists on the same board
- Status lists are only available with appropriate license
Checks
This ensures board lists tied to status are only created when the entire status feature set is active, all of the following has to be enabled:
- The
board_status_listslicensed feature - The
work_item_statuslicensed features - The
work_item_status_feature_flagfeature flag
Notes
- This MR builds on top of the placeholder API introduced via Add statusId argument to boardListCreate mutation MR.
- This MR doesn't yet include functionality to query status details for a board list once it's created. The placeholder API still returns nil. I'll address that in a separate MR shortly.
- As per our decision registry, we're implementing support for statuses in legacy issue boards, since the new board experience won't be ready for GA by July 2025.
References
- BE: Implement support for status in board list services
- BE: DB migrations to support status on issue boards
- BE: Add status support for GraphQL board list queries and mutations
- Status lists on legacy issue boards
- Work Items Custom Status Design Doc
- Configurable Work Item Statuses Epic
Screenshots or screen recordings
backend only
How to set up and validate locally
- Enable the
work_item_status_feature_flagfeature flag. - Create a new issue board under
flightjs/Flightproject. - Use the mutation below to create a new issue board list based on the following scenarios:
Scenario 1: With a valid system-defined status
View mutation
mutation createBoardListEE(
$boardId: BoardID!
$backlog: Boolean
$labelId: LabelID
$milestoneId: MilestoneID
$iterationId: IterationID
$assigneeId: UserID
$statusId: WorkItemsStatusesStatusID
$position: Int
) {
boardListCreate(
input: {
boardId: $boardId
backlog: $backlog
labelId: $labelId
milestoneId: $milestoneId
iterationId: $iterationId
assigneeId: $assigneeId
statusId: $statusId
position: $position
}
) {
list {
id
title
}
errors
}
}
{
"boardId": "gid://gitlab/Board/6", # TODO: Replace with your board GID
"statusId": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1"
}
View response
{
"data": {
"boardListCreate": {
"list": {
"id": "gid://gitlab/List/30",
"title": "To do"
},
"errors": []
}
},
"correlationId": "01JV1FGVD3GWXCA0H4JDEB75KC"
}
Scenario 2: With an invalid system-defined status
View mutation
mutation createBoardListEE(
$boardId: BoardID!
$backlog: Boolean
$labelId: LabelID
$milestoneId: MilestoneID
$iterationId: IterationID
$assigneeId: UserID
$statusId: WorkItemsStatusesStatusID
$position: Int
) {
boardListCreate(
input: {
boardId: $boardId
backlog: $backlog
labelId: $labelId
milestoneId: $milestoneId
iterationId: $iterationId
assigneeId: $assigneeId
statusId: $statusId
position: $position
}
) {
list {
id
title
}
errors
}
}
{
"boardId": "gid://gitlab/Board/6", # TODO: Replace with your board GID
"statusId": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/10"
}
View response
{
"data": {
"boardListCreate": {
"list": null,
"errors": [
"Status not found"
]
}
},
"correlationId": "01JV1CR5V7E0VSDTV6N346FGAG"
}
Scenario 3: With a valid custom status
Prerequisites
- Create a custom lifecycle and statuses via Rails console.
Click to expand
- Find a namespace
project = Project.find(7) # flightjs/Flight
namespace = project.root_ancestor
- Create a custom status for a given namespace
WorkItems::Statuses::Custom::Status.create!(
namespace: namespace,
name: "To do",
color: "#737278",
category: :to_do
)
- Run the mutation and verify the response
View mutation
mutation createBoardListEE(
$boardId: BoardID!
$backlog: Boolean
$labelId: LabelID
$milestoneId: MilestoneID
$iterationId: IterationID
$assigneeId: UserID
$statusId: WorkItemsStatusesStatusID
$position: Int
) {
boardListCreate(
input: {
boardId: $boardId
backlog: $backlog
labelId: $labelId
milestoneId: $milestoneId
iterationId: $iterationId
assigneeId: $assigneeId
statusId: $statusId
position: $position
}
) {
list {
id
title
}
errors
}
}
{
"boardId": "gid://gitlab/Board/6", # TODO: Replace with your board GID
"statusId": "gid://gitlab/WorkItems::Statuses::Custom::Status/60" # TODO: Replace with your ID
}
View response
{
"data": {
"boardListCreate": {
"list": {
"id": "gid://gitlab/List/31",
"title": "To do"
},
"errors": []
}
},
"correlationId": "01JV3X88SR47QAJEFN25TE8693"
}
Scenario 4: With an invalid custom status
View mutation
mutation createBoardListEE(
$boardId: BoardID!
$backlog: Boolean
$labelId: LabelID
$milestoneId: MilestoneID
$iterationId: IterationID
$assigneeId: UserID
$statusId: WorkItemsStatusesStatusID
$position: Int
) {
boardListCreate(
input: {
boardId: $boardId
backlog: $backlog
labelId: $labelId
milestoneId: $milestoneId
iterationId: $iterationId
assigneeId: $assigneeId
statusId: $statusId
position: $position
}
) {
list {
id
title
}
errors
}
}
{
"boardId": "gid://gitlab/Board/6", # TODO: Replace with your board GID
"statusId": "gid://gitlab/WorkItems::Statuses::Custom::Status/100"
}
View response
{
"data": {
"boardListCreate": {
"list": null,
"errors": [
"Status not found"
]
}
},
"correlationId": "01JV1F7K4MRW6Z070ZEXCVT763"
}
Post-testing cleanup
WorkItems::Statuses::Custom::Status.destroy_all
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Edited by Agnes Slota