Implement status batch loading for work items
What does this MR do and why?
- Solves: Implement BulkStatusResolver to efficiently fetch statuses & Introduce status field and type as container for status & Use array of status type instead of connection_type
- Contributes to: BE: Implement GraphQl APIs
--
As part of the first iteration of the configurable work item statuses initiative, we would like to implement efficient status retrieval functionality for work items using batch loading. The new API will be used to provide fetched statuses to work items when we fetch lists of work items in the frontend.
Changes
- Introduce the
WorkItems::Statuses::BulkStatusResolver
that uses BatchLoader to optimize and avoid N+1 SQL queries when loading statuses for multiple work items. - Expose the
status
field onWorkItemWidgetStatus
GraphQL type that uses theWorkItems::Statuses::BulkStatusResolver
for returning work item statuses. - Change the
allowedStatuses
field onWorkItemWidgetDefinitionStatus
GraphQL type from a connection type to an array of status types to remove the unnecessary pagination layer for statuses. - Remove the redundant
allowedStatuses
field from theGroup
,Project
andNamespace
types.
Notes
- This implementation focuses on system-defined statuses only for iteration 1. Custom status handling will be implemented in iteration 2.
- The initial implementation was introduced as part of this POC MR.
- The deprecation process is not required as this MR updates the experimental API.
GraphQL queries
WorkItemWidgetStatus
Group namespace
View query
query GroupWorkItems($groupPath: ID!, $first: Int = 3) {
group(fullPath: $groupPath) {
id
name
workItems(first: $first, sort: CREATED_DESC, types: [TASK]) {
nodes {
id
title
widgets {
type
... on WorkItemWidgetStatus {
status {
id
name
color
iconName
position
}
}
}
}
}
}
}
{
"groupPath": "gitlab-org",
"first": 3
}
Scenario 1: with a mix of current statuses available and not available
View response
{
"data": {
"group": {
"id": "gid://gitlab/Group/24",
"name": "Gitlab Org",
"workItems": {
"nodes": [
{
"id": "gid://gitlab/WorkItem/676",
"title": "Task 3 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": {
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1",
"name": "To do",
"color": "#737278",
"iconName": "status-waiting",
"position": 0
}
}
]
},
{
"id": "gid://gitlab/WorkItem/675",
"title": "Task 2 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
},
{
"id": "gid://gitlab/WorkItem/674",
"title": "Task 1 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": {
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/2",
"name": "In progress",
"color": "#1f75cb",
"iconName": "status-running",
"position": 0
}
}
]
}
]
}
}
},
"correlationId": "01JP6Z7GBDFNX3S181197HWM19"
}
Scenario 2: with current statuses not available
View response
{
"data": {
"group": {
"id": "gid://gitlab/Group/24",
"name": "Gitlab Org",
"workItems": {
"nodes": [
{
"id": "gid://gitlab/WorkItem/676",
"title": "Task 3 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
},
{
"id": "gid://gitlab/WorkItem/675",
"title": "Task 2 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
},
{
"id": "gid://gitlab/WorkItem/674",
"title": "Task 1 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
}
]
}
}
},
"correlationId": "01JP6KE6Z0HVYVR92KRJ4B756S"
}
Scenario 3: with the work_item_status_feature_flag
FF disabled
View response
{
"data": {
"group": {
"id": "gid://gitlab/Group/24",
"name": "Gitlab Org",
"workItems": {
"nodes": [
{
"id": "gid://gitlab/WorkItem/676",
"title": "Task 3 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
},
{
"id": "gid://gitlab/WorkItem/675",
"title": "Task 2 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
},
{
"id": "gid://gitlab/WorkItem/674",
"title": "Task 1 | 2025-03-13",
"widgets": [
{
"type": "ASSIGNEES"
},
{
"type": "AWARD_EMOJI"
},
{
"type": "CRM_CONTACTS"
},
{
"type": "CURRENT_USER_TODOS"
},
{
"type": "CUSTOM_FIELDS"
},
{
"type": "DESCRIPTION"
},
{
"type": "DEVELOPMENT"
},
{
"type": "HIERARCHY"
},
{
"type": "ITERATION"
},
{
"type": "LABELS"
},
{
"type": "LINKED_ITEMS"
},
{
"type": "MILESTONE"
},
{
"type": "NOTES"
},
{
"type": "NOTIFICATIONS"
},
{
"type": "PARTICIPANTS"
},
{
"type": "START_AND_DUE_DATE"
},
{
"type": "TIME_TRACKING"
},
{
"type": "WEIGHT"
},
{
"type": "STATUS",
"status": null
}
]
}
]
}
}
},
"correlationId": "01JP9QZSH1B2DC4P6QX8ARZDP7"
}
Project namespace
View query
query getWorkItems(
$fullPath: ID!
$search: String
$sort: WorkItemSort
$state: IssuableState
$assigneeWildcardId: AssigneeWildcardId
$assigneeUsernames: [String!]
$authorUsername: String
$confidential: Boolean
$labelName: [String!]
$milestoneTitle: [String!]
$milestoneWildcardId: MilestoneWildcardId
$myReactionEmoji: String
$types: [IssueType!]
$in: [IssuableSearchableField!]
$not: NegatedWorkItemFilterInput
$or: UnionedWorkItemFilterInput
$afterCursor: String
$beforeCursor: String
$firstPageSize: Int
$lastPageSize: Int
$isGroup: Boolean = true
$excludeProjects: Boolean
) {
group(fullPath: $fullPath) @include(if: $isGroup) {
id
name
workItems(
excludeProjects: $excludeProjects
includeDescendants: true
search: $search
sort: $sort
state: $state
assigneeUsernames: $assigneeUsernames
assigneeWildcardId: $assigneeWildcardId
authorUsername: $authorUsername
confidential: $confidential
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
myReactionEmoji: $myReactionEmoji
types: $types
in: $in
not: $not
or: $or
after: $afterCursor
before: $beforeCursor
first: $firstPageSize
last: $lastPageSize
) {
pageInfo {
...PageInfo
__typename
}
nodes {
id
author {
id
name
username
__typename
}
iid
namespace {
id
fullPath
__typename
}
reference(full: true)
state
title
updatedAt
webUrl
widgets {
type
...WorkItemWidgets
__typename
}
workItemType {
id
name
__typename
}
__typename
}
__typename
}
__typename
}
project(fullPath: $fullPath) @skip(if: $isGroup) {
id
name
workItems(
search: $search
sort: $sort
state: $state
assigneeUsernames: $assigneeUsernames
assigneeWildcardId: $assigneeWildcardId
authorUsername: $authorUsername
confidential: $confidential
labelName: $labelName
milestoneTitle: $milestoneTitle
milestoneWildcardId: $milestoneWildcardId
myReactionEmoji: $myReactionEmoji
types: $types
in: $in
not: $not
or: $or
after: $afterCursor
before: $beforeCursor
first: $firstPageSize
last: $lastPageSize
) {
pageInfo {
...PageInfo
__typename
}
nodes {
id
author {
id
name
username
__typename
}
iid
namespace {
id
fullPath
__typename
}
reference(full: true)
state
title
updatedAt
webUrl
widgets {
type
...WorkItemWidgets
__typename
}
workItemType {
id
name
__typename
}
__typename
}
__typename
}
__typename
}
}
fragment PageInfo on PageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
__typename
}
fragment WorkItemWidgets on WorkItemWidget {
... on WorkItemWidgetStatus {
status {
id
name
iconName
color
position
__typename
}
__typename
}
__typename
}
{
"isGroup": false,
"fullPath": "gitlab-org/gitlab-test",
"sort": "CREATED_DESC",
"state": "opened",
"types": "TASK",
"firstPageSize": 20,
"excludeProjects": false
}
Scenario 1: with a mix of current statuses available and not available
View response
{
"data": {
"project": {
"id": "gid://gitlab/Project/2",
"name": "Gitlab Test",
"workItems": {
"pageInfo": {
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OTozMC43NTUyMzEwMDAgKzAwMDAiLCJpZCI6IjY4MiJ9",
"endCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OToxNi43OTA5MzAwMDAgKzAwMDAiLCJpZCI6IjY4MCJ9",
"__typename": "PageInfo"
},
"nodes": [
{
"id": "gid://gitlab/WorkItem/682",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "56",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#56",
"state": "OPEN",
"title": "Task 3 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:30Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/56",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": {
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/2",
"name": "In progress",
"iconName": "status-running",
"color": "#1f75cb",
"position": 0,
"__typename": "WorkItemStatus"
},
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/681",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "55",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#55",
"state": "OPEN",
"title": "Task 2 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:24Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/55",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/680",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "54",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#54",
"state": "OPEN",
"title": "Task 1 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:16Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/54",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": {
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1",
"name": "To do",
"iconName": "status-waiting",
"color": "#737278",
"position": 0,
"__typename": "WorkItemStatus"
},
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
}
],
"__typename": "WorkItemConnection"
},
"__typename": "Project"
}
},
"correlationId": "01JPGY4QCJ4KZ8FTRPX9NFND0K"
}
Scenario 2: with current statuses not available
View response
{
"data": {
"project": {
"id": "gid://gitlab/Project/2",
"name": "Gitlab Test",
"workItems": {
"pageInfo": {
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OTozMC43NTUyMzEwMDAgKzAwMDAiLCJpZCI6IjY4MiJ9",
"endCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OToxNi43OTA5MzAwMDAgKzAwMDAiLCJpZCI6IjY4MCJ9",
"__typename": "PageInfo"
},
"nodes": [
{
"id": "gid://gitlab/WorkItem/682",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "56",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#56",
"state": "OPEN",
"title": "Task 3 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:30Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/56",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/681",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "55",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#55",
"state": "OPEN",
"title": "Task 2 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:24Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/55",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/680",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "54",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#54",
"state": "OPEN",
"title": "Task 1 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:16Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/54",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
}
],
"__typename": "WorkItemConnection"
},
"__typename": "Project"
}
},
"correlationId": "01JPGXD0K2CXTD0BEHPW9SDC3Z"
}
Scenario 3: with the work_item_status_feature_flag
FF disabled
View response
{
"data": {
"project": {
"id": "gid://gitlab/Project/2",
"name": "Gitlab Test",
"workItems": {
"pageInfo": {
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OTozMC43NTUyMzEwMDAgKzAwMDAiLCJpZCI6IjY4MiJ9",
"endCursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS0wMy0xNyAwMTo1OToxNi43OTA5MzAwMDAgKzAwMDAiLCJpZCI6IjY4MCJ9",
"__typename": "PageInfo"
},
"nodes": [
{
"id": "gid://gitlab/WorkItem/682",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "56",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#56",
"state": "OPEN",
"title": "Task 3 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:30Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/56",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/681",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "55",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#55",
"state": "OPEN",
"title": "Task 2 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:24Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/55",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
},
{
"id": "gid://gitlab/WorkItem/680",
"author": {
"id": "gid://gitlab/User/1",
"name": "Administrator",
"username": "root",
"__typename": "UserCore"
},
"iid": "54",
"namespace": {
"id": "gid://gitlab/Namespaces::ProjectNamespace/25",
"fullPath": "gitlab-org/gitlab-test",
"__typename": "Namespace"
},
"reference": "gitlab-org/gitlab-test#54",
"state": "OPEN",
"title": "Task 1 | 184128 | 2025-03-17",
"updatedAt": "2025-03-17T01:59:16Z",
"webUrl": "http://127.0.0.1:3000/gitlab-org/gitlab-test/-/work_items/54",
"widgets": [
{
"type": "ASSIGNEES",
"__typename": "WorkItemWidgetAssignees"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "CRM_CONTACTS",
"__typename": "WorkItemWidgetCrmContacts"
},
{
"type": "CURRENT_USER_TODOS",
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "CUSTOM_FIELDS",
"__typename": "WorkItemWidgetCustomFields"
},
{
"type": "DESCRIPTION",
"__typename": "WorkItemWidgetDescription"
},
{
"type": "DEVELOPMENT",
"__typename": "WorkItemWidgetDevelopment"
},
{
"type": "HIERARCHY",
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "ITERATION",
"__typename": "WorkItemWidgetIteration"
},
{
"type": "LABELS",
"__typename": "WorkItemWidgetLabels"
},
{
"type": "LINKED_ITEMS",
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "MILESTONE",
"__typename": "WorkItemWidgetMilestone"
},
{
"type": "NOTES",
"__typename": "WorkItemWidgetNotes"
},
{
"type": "NOTIFICATIONS",
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "START_AND_DUE_DATE",
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "TIME_TRACKING",
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "WEIGHT",
"__typename": "WorkItemWidgetWeight"
},
{
"type": "STATUS",
"status": null,
"__typename": "WorkItemWidgetStatus"
}
],
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"__typename": "WorkItemType"
},
"__typename": "WorkItem"
}
],
"__typename": "WorkItemConnection"
},
"__typename": "Project"
}
},
"correlationId": "01JPGXVJV29B534EN6R48QC76G"
}
WorkItemWidgetDefinitionStatus
Below, you can find test queries to fetch allowed statuses for a given work item type:
Scenario 1: when the work item type is supported
View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
workspace: namespace(fullPath: $fullPath) {
id
workItemTypes(name: $name) {
nodes {
id
name
widgetDefinitions {
... on WorkItemWidgetDefinitionStatus {
allowedStatuses {
id
name
iconName
color
position
}
}
}
__typename
}
__typename
}
__typename
}
}
{
"fullPath": "gitlab-org",
"name": "TASK"
}
View response
{
"data": {
"workspace": {
"id": "gid://gitlab/Group/24",
"workItemTypes": {
"nodes": [
{
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"widgetDefinitions": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{
"allowedStatuses": [
{
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1",
"name": "To do",
"iconName": "status-waiting",
"color": "#737278",
"position": 0
},
{
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/2",
"name": "In progress",
"iconName": "status-running",
"color": "#1f75cb",
"position": 0
},
{
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/3",
"name": "Done",
"iconName": "status-success",
"color": "#108548",
"position": 0
},
{
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/4",
"name": "Won't do",
"iconName": "status-cancelled",
"color": "#DD2B0E",
"position": 0
},
{
"id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/5",
"name": "Duplicate",
"iconName": "status-cancelled",
"color": "#DD2B0E",
"position": 10
}
]
}
],
"__typename": "WorkItemType"
}
],
"__typename": "WorkItemTypeConnection"
},
"__typename": "Namespace"
}
},
"correlationId": "01JP42GFCX3DDGRBV7H9T4A104"
}
Scenario 2: when the work item type is not supported
View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
workspace: namespace(fullPath: $fullPath) {
id
workItemTypes(name: $name) {
nodes {
id
name
widgetDefinitions {
... on WorkItemWidgetDefinitionStatus {
allowedStatuses {
id
name
iconName
color
position
}
}
}
__typename
}
__typename
}
__typename
}
}
{
"fullPath": "gitlab-org",
"name": "EPIC"
}
View response
{
"data": {
"workspace": {
"id": "gid://gitlab/Group/24",
"workItemTypes": {
"nodes": [
{
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"widgetDefinitions": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{}
],
"__typename": "WorkItemType"
}
],
"__typename": "WorkItemTypeConnection"
},
"__typename": "Namespace"
}
},
"correlationId": "01JP42JSW99K5F43YH4XHEVK8P"
}
Scenario 3: when the work_item_status_feature_flag
FF is disabled
View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
workspace: namespace(fullPath: $fullPath) {
id
workItemTypes(name: $name) {
nodes {
id
name
widgetDefinitions {
... on WorkItemWidgetDefinitionStatus {
allowedStatuses {
id
name
iconName
color
position
}
}
}
__typename
}
__typename
}
__typename
}
}
{
"fullPath": "gitlab-org",
"name": "TASK"
}
View response
{
"data": {
"workspace": {
"id": "gid://gitlab/Group/24",
"workItemTypes": {
"nodes": [
{
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"widgetDefinitions": [
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{
"allowedStatuses": []
}
],
"__typename": "WorkItemType"
}
],
"__typename": "WorkItemTypeConnection"
},
"__typename": "Namespace"
}
},
"correlationId": "01JP42NM3PJH3KC4HBM9DRJKW9"
}
SQL query
Here's an example SQL query produced by the BulkStatusResolver
after fetching the latest three work items of type task:
SELECT "work_item_current_statuses".*
FROM "work_item_current_statuses"
WHERE "work_item_current_statuses"."work_item_id" IN (676, 675, 674)
The query demonstrates the core of the status batch loading functionality. It fetches statuses for multiple work items (676
, 675
, 674
) in a single database call.
Here's a query plan analysing the above SQL query using the latest three production work items that belong to gitlab-org/gitlab
project. Please note, that the work_item_current_statuses
table is currently empty, as we're gradually implementing functionality to assign current status to work items.
As per the discussion here, we're deferring further testing until BE: Backfill status data for work items (#517342). As part of that issue, we'll run the query plans in production and verify that work item statuses are efficiently batch loaded by BulkStatusResolver
.
References
Please include cross links to any resources that are relevant to this MR. This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.
- Implement BulkStatusResolver to efficiently fetch statuses
- Introduce status field and type as container for status
- Use array of status type instead of connection_type
- BE: Implement GraphQl APIs
- Work items custom status design document
- Configurable Work Item Statuses Epic
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Screenshots or screen recordings
Screenshots are required for UI changes, and strongly recommended for all other merge requests.
backend changes only
How to set up and validate locally
Numbered steps to set up and validate the change are strongly suggested.
- Enable the
namespace_level_work_items
feature flag to have access to work items. - Create a few work item tasks and follow instructions here to manually assign current statuses.
- Navigate to the GraphQL Explorer: http://127.0.0.1:3000/-/graphql-explorer.
- Use the test queries provided above. Depending on a test scenario, enable or disable
work_item_status_feature_flag
feature flag. - Verify the response data.