Use new work item way to make JH epic milestone/iteration keep working
用户描述
What does this MR do and why?
[OLD] Use new work item way to make JH epic milestone/iteration keep working
Upstream prepend_mod MR here: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183641
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.
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.
How to set up and validate locally
Use these NEW graphql requests
Create epic
Graphql params:
mutation createWorkItem($input: WorkItemCreateInput!) {
workItemCreate(input: $input) {
workItem {
...WorkItem
__typename
}
errors
__typename
}
}
fragment WorkItem on WorkItem {
id
iid
archived
title
state
description
confidential
createdAt
closedAt
webUrl
reference(full: true)
createNoteEmail
project {
id
__typename
}
namespace {
id
fullPath
name
fullName
__typename
}
author {
...Author
__typename
}
workItemType {
id
name
iconName
__typename
}
userPermissions {
deleteWorkItem
updateWorkItem
adminParentLink
setWorkItemMetadata
createNote
adminWorkItemLink
markNoteAsInternal
__typename
}
widgets {
...WorkItemWidgets
__typename
}
jhIteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
fragment WorkItemWidgets on WorkItemWidget {
type
... on WorkItemWidgetDescription {
description
descriptionHtml
lastEditedAt
lastEditedBy {
name
webPath
__typename
}
taskCompletionStatus {
completedCount
count
__typename
}
__typename
}
... on WorkItemWidgetAssignees {
allowsMultipleAssignees
canInviteMembers
assignees {
nodes {
...User
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetLabels {
allowsScopedLabels
labels {
nodes {
...Label
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetStartAndDueDate {
dueDate
startDate
rollUp
isFixed
__typename
}
... on WorkItemWidgetTimeTracking {
timeEstimate
timelogs {
nodes {
...TimelogFragment
__typename
}
__typename
}
totalTimeSpent
__typename
}
... on WorkItemWidgetWeight {
weight
rolledUpWeight
rolledUpCompletedWeight
widgetDefinition {
editable
rollUp
__typename
}
__typename
}
... on WorkItemWidgetProgress {
progress
updatedAt
__typename
}
... on WorkItemWidgetHierarchy {
hasChildren
hasParent
rolledUpCountsByType {
countsByState {
opened
all
closed
__typename
}
workItemType {
id
name
iconName
__typename
}
__typename
}
parent {
id
iid
title
confidential
webUrl
workItemType {
id
name
iconName
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetIteration {
iteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetMilestone {
milestone {
...MilestoneFragment
__typename
}
__typename
}
... on WorkItemWidgetNotes {
discussionLocked
__typename
}
... on WorkItemWidgetHealthStatus {
healthStatus
rolledUpHealthStatus {
count
healthStatus
__typename
}
__typename
}
... on WorkItemWidgetNotifications {
subscribed
__typename
}
... on WorkItemWidgetCurrentUserTodos {
currentUserTodos(state: pending) {
nodes {
id
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetColor {
color
textColor
__typename
}
... on WorkItemWidgetLinkedItems {
linkedItems {
nodes {
linkId
linkType
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetCrmContacts {
contacts {
nodes {
id
email
firstName
lastName
phone
description
organization {
id
name
description
defaultRate
__typename
}
__typename
}
__typename
}
__typename
}
__typename
}
fragment Label on Label {
id
title
description
color
textColor
__typename
}
fragment User on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
fragment MilestoneFragment on Milestone {
expired
id
title
state
startDate
dueDate
webPath
__typename
}
fragment TimelogFragment on WorkItemTimelog {
__typename
id
timeSpent
user {
id
name
__typename
}
spentAt
note {
id
body
__typename
}
summary
userPermissions {
adminTimelog
__typename
}
}
fragment Author on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
Graphql input:
{
"input": {
"title": "JH Epic 2025 002",
"workItemTypeId": "gid://gitlab/WorkItems::Type/8",
"namespacePath": "tragedxy",
"confidential": false,
"milestoneWidget": {
"milestoneId": "gid://gitlab/Milestone/67"
},
"iterationWidget": {
"iterationId": "gid://gitlab/Iteration/83422"
},
"descriptionWidget": {
"description": "JH Epic 2025 002!!"
},
"colorWidget": {
"color": "#1068bf"
},
"labelsWidget": {
"labelIds": []
},
"weightWidget": {
"weight": null
},
"startAndDueDateWidget": {
"isFixed": true,
"startDate": "2025-01-07",
"dueDate": "2025-01-31"
}
}
}
Response:
{
"data": {
"workItemCreate": {
"workItem": {
"id": "gid://gitlab/WorkItem/810",
"iid": "112",
"archived": false,
"title": "JH Epic 2025 002",
"state": "OPEN",
"description": "JH Epic 2025 002!!",
"confidential": false,
"createdAt": "2025-03-10T06:39:25Z",
"closedAt": null,
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/epics/112",
"reference": "tragedxy#112",
"createNoteEmail": null,
"project": null,
"namespace": {
"id": "gid://gitlab/Group/72",
"fullPath": "tragedxy",
"name": "Tragedxy",
"fullName": "Tragedxy",
"__typename": "Namespace"
},
"author": {
"id": "gid://gitlab/User/1",
"avatarUrl": "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon",
"name": "Administrator",
"username": "root",
"webUrl": "http://gdk.test:3000/root",
"webPath": "/root",
"__typename": "UserCore"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"userPermissions": {
"deleteWorkItem": true,
"updateWorkItem": true,
"adminParentLink": true,
"setWorkItemMetadata": true,
"createNote": true,
"adminWorkItemLink": true,
"markNoteAsInternal": true,
"__typename": "WorkItemPermissions"
},
"widgets": [
{
"type": "DESCRIPTION",
"description": "JH Epic 2025 002!!",
"descriptionHtml": "<p data-sourcepos=\"1:1-1:18\" dir=\"auto\">JH Epic 2025 002!!</p>",
"lastEditedAt": null,
"lastEditedBy": null,
"taskCompletionStatus": {
"completedCount": 0,
"count": 0,
"__typename": "TaskCompletionStatus"
},
"__typename": "WorkItemWidgetDescription"
},
{
"type": "HIERARCHY",
"hasChildren": false,
"hasParent": false,
"rolledUpCountsByType": [
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/1",
"name": "Issue",
"iconName": "issue-type-issue",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"iconName": "issue-type-task",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
}
],
"parent": null,
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "LABELS",
"allowsScopedLabels": true,
"labels": {
"nodes": [],
"__typename": "LabelConnection"
},
"__typename": "WorkItemWidgetLabels"
},
{
"type": "NOTES",
"discussionLocked": null,
"__typename": "WorkItemWidgetNotes"
},
{
"type": "START_AND_DUE_DATE",
"dueDate": "2025-01-31",
"startDate": "2025-01-07",
"rollUp": true,
"isFixed": true,
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "HEALTH_STATUS",
"healthStatus": null,
"rolledUpHealthStatus": [
{
"count": 0,
"healthStatus": "onTrack",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "needsAttention",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "atRisk",
"__typename": "WorkItemWidgetHealthStatusCount"
}
],
"__typename": "WorkItemWidgetHealthStatus"
},
{
"type": "NOTIFICATIONS",
"subscribed": true,
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "STATUS",
"__typename": "WorkItemWidgetStatus"
},
{
"type": "LINKED_ITEMS",
"linkedItems": {
"nodes": [],
"__typename": "LinkedWorkItemTypeConnection"
},
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "CURRENT_USER_TODOS",
"currentUserTodos": {
"nodes": [],
"__typename": "TodoConnection"
},
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "COLOR",
"color": "#1068bf",
"textColor": "#FFFFFF",
"__typename": "WorkItemWidgetColor"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "WEIGHT",
"weight": null,
"rolledUpWeight": null,
"rolledUpCompletedWeight": null,
"widgetDefinition": {
"editable": false,
"rollUp": true,
"__typename": "WorkItemWidgetDefinitionWeight"
},
"__typename": "WorkItemWidgetWeight"
},
{
"type": "TIME_TRACKING",
"timeEstimate": 0,
"timelogs": {
"nodes": [],
"__typename": "WorkItemTimelogConnection"
},
"totalTimeSpent": 0,
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "MILESTONE",
"milestone": {
"expired": false,
"id": "gid://gitlab/Milestone/67",
"title": "MST 2025-301",
"state": "active",
"startDate": "2025-03-01",
"dueDate": "2025-03-31",
"webPath": "/groups/tragedxy/-/milestones/5",
"__typename": "Milestone"
},
"__typename": "WorkItemWidgetMilestone"
}
],
"jhIteration": {
"id": "gid://gitlab/Iteration/83422",
"title": null,
"startDate": "2025-02-17",
"dueDate": "2025-03-16",
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/iterations/83422",
"iterationCadence": {
"id": "gid://gitlab/Iterations::Cadence/8004",
"title": "2025-Q1",
"__typename": "IterationCadence"
},
"__typename": "Iteration"
},
"__typename": "WorkItem"
},
"errors": [],
"__typename": "WorkItemCreatePayload"
}
}
}
Upgrade epic
Graphql param:
mutation workItemUpdate($input: WorkItemUpdateInput!) {
workItemUpdate(input: $input) {
workItem {
...WorkItem
__typename
}
errors
__typename
}
}
fragment WorkItem on WorkItem {
id
iid
archived
title
state
description
confidential
createdAt
closedAt
webUrl
reference(full: true)
createNoteEmail
project {
id
__typename
}
namespace {
id
fullPath
name
__typename
}
author {
...Author
__typename
}
workItemType {
id
name
iconName
__typename
}
userPermissions {
deleteWorkItem
updateWorkItem
adminParentLink
setWorkItemMetadata
createNote
adminWorkItemLink
markNoteAsInternal
__typename
}
widgets {
...WorkItemWidgets
__typename
}
jhIteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
fragment WorkItemWidgets on WorkItemWidget {
type
... on WorkItemWidgetDescription {
description
descriptionHtml
lastEditedAt
lastEditedBy {
name
webPath
__typename
}
taskCompletionStatus {
completedCount
count
__typename
}
__typename
}
... on WorkItemWidgetAssignees {
allowsMultipleAssignees
canInviteMembers
assignees {
nodes {
...User
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetLabels {
allowsScopedLabels
labels {
nodes {
...Label
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetStartAndDueDate {
dueDate
startDate
rollUp
isFixed
__typename
}
... on WorkItemWidgetTimeTracking {
timeEstimate
timelogs {
nodes {
...TimelogFragment
__typename
}
__typename
}
totalTimeSpent
__typename
}
... on WorkItemWidgetWeight {
weight
rolledUpWeight
rolledUpCompletedWeight
widgetDefinition {
editable
rollUp
__typename
}
__typename
}
... on WorkItemWidgetProgress {
progress
updatedAt
__typename
}
... on WorkItemWidgetHierarchy {
hasChildren
hasParent
rolledUpCountsByType {
countsByState {
opened
all
closed
__typename
}
workItemType {
id
name
iconName
__typename
}
__typename
}
parent {
id
iid
title
confidential
webUrl
workItemType {
id
name
iconName
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetIteration {
iteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetMilestone {
milestone {
...MilestoneFragment
__typename
}
__typename
}
... on WorkItemWidgetNotes {
discussionLocked
__typename
}
... on WorkItemWidgetHealthStatus {
healthStatus
rolledUpHealthStatus {
count
healthStatus
__typename
}
__typename
}
... on WorkItemWidgetNotifications {
subscribed
__typename
}
... on WorkItemWidgetCurrentUserTodos {
currentUserTodos(state: pending) {
nodes {
id
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetColor {
color
textColor
__typename
}
... on WorkItemWidgetLinkedItems {
linkedItems {
nodes {
linkId
linkType
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetCrmContacts {
contacts {
nodes {
id
email
firstName
lastName
phone
description
organization {
id
name
description
defaultRate
__typename
}
__typename
}
__typename
}
__typename
}
__typename
}
fragment Label on Label {
id
title
description
color
textColor
__typename
}
fragment User on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
fragment MilestoneFragment on Milestone {
expired
id
title
state
startDate
dueDate
webPath
__typename
}
fragment TimelogFragment on WorkItemTimelog {
__typename
id
timeSpent
user {
id
name
__typename
}
spentAt
note {
id
body
__typename
}
summary
userPermissions {
adminTimelog
__typename
}
}
fragment Author on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
Graphql input:
{
"input": {
"id": "gid://gitlab/WorkItem/759",
"milestoneWidget": {
"milestoneId": "gid://gitlab/Milestone/66"
},
"iterationWidget": {
"iterationId": "gid://gitlab/Iteration/83422"
}
}
}
Response:
{
"data": {
"workItemUpdate": {
"workItem": {
"id": "gid://gitlab/WorkItem/759",
"iid": "68",
"archived": false,
"title": "JH Epic 2025 002",
"state": "OPEN",
"description": "JH Epic 2025 002!!",
"confidential": false,
"createdAt": "2025-02-21T09:52:00Z",
"closedAt": null,
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/epics/68",
"reference": "tragedxy#68",
"createNoteEmail": null,
"project": null,
"namespace": {
"id": "gid://gitlab/Group/72",
"fullPath": "tragedxy",
"name": "Tragedxy",
"__typename": "Namespace"
},
"author": {
"id": "gid://gitlab/User/1",
"avatarUrl": "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon",
"name": "Administrator",
"username": "root",
"webUrl": "http://gdk.test:3000/root",
"webPath": "/root",
"__typename": "UserCore"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"userPermissions": {
"deleteWorkItem": true,
"updateWorkItem": true,
"adminParentLink": true,
"setWorkItemMetadata": true,
"createNote": true,
"adminWorkItemLink": true,
"markNoteAsInternal": true,
"__typename": "WorkItemPermissions"
},
"widgets": [
{
"type": "DESCRIPTION",
"description": "JH Epic 2025 002!!",
"descriptionHtml": "<p data-sourcepos=\"1:1-1:18\" dir=\"auto\">JH Epic 2025 002!!</p>",
"lastEditedAt": null,
"lastEditedBy": null,
"taskCompletionStatus": {
"completedCount": 0,
"count": 0,
"__typename": "TaskCompletionStatus"
},
"__typename": "WorkItemWidgetDescription"
},
{
"type": "HIERARCHY",
"hasChildren": false,
"hasParent": false,
"rolledUpCountsByType": [
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/1",
"name": "Issue",
"iconName": "issue-type-issue",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"iconName": "issue-type-task",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
}
],
"parent": null,
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "LABELS",
"allowsScopedLabels": true,
"labels": {
"nodes": [],
"__typename": "LabelConnection"
},
"__typename": "WorkItemWidgetLabels"
},
{
"type": "NOTES",
"discussionLocked": null,
"__typename": "WorkItemWidgetNotes"
},
{
"type": "START_AND_DUE_DATE",
"dueDate": "2025-01-31",
"startDate": "2025-01-07",
"rollUp": true,
"isFixed": true,
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "HEALTH_STATUS",
"healthStatus": null,
"rolledUpHealthStatus": [
{
"count": 0,
"healthStatus": "onTrack",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "needsAttention",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "atRisk",
"__typename": "WorkItemWidgetHealthStatusCount"
}
],
"__typename": "WorkItemWidgetHealthStatus"
},
{
"type": "NOTIFICATIONS",
"subscribed": true,
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "STATUS",
"__typename": "WorkItemWidgetStatus"
},
{
"type": "LINKED_ITEMS",
"linkedItems": {
"nodes": [],
"__typename": "LinkedWorkItemTypeConnection"
},
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "CURRENT_USER_TODOS",
"currentUserTodos": {
"nodes": [],
"__typename": "TodoConnection"
},
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "COLOR",
"color": "#4dd787",
"textColor": "#1F1E24",
"__typename": "WorkItemWidgetColor"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "WEIGHT",
"weight": null,
"rolledUpWeight": null,
"rolledUpCompletedWeight": null,
"widgetDefinition": {
"editable": false,
"rollUp": true,
"__typename": "WorkItemWidgetDefinitionWeight"
},
"__typename": "WorkItemWidgetWeight"
},
{
"type": "TIME_TRACKING",
"timeEstimate": 0,
"timelogs": {
"nodes": [],
"__typename": "WorkItemTimelogConnection"
},
"totalTimeSpent": 0,
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "MILESTONE",
"milestone": {
"expired": true,
"id": "gid://gitlab/Milestone/66",
"title": "MST 2025-101",
"state": "active",
"startDate": "2025-01-20",
"dueDate": "2025-02-20",
"webPath": "/groups/tragedxy/-/milestones/4",
"__typename": "Milestone"
},
"__typename": "WorkItemWidgetMilestone"
}
],
"jhIteration": {
"id": "gid://gitlab/Iteration/83422",
"title": null,
"startDate": "2025-02-17",
"dueDate": "2025-03-16",
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/iterations/83422",
"iterationCadence": {
"id": "gid://gitlab/Iterations::Cadence/8004",
"title": "2025-Q1",
"__typename": "IterationCadence"
},
"__typename": "Iteration"
},
"__typename": "WorkItem"
},
"errors": [],
"__typename": "WorkItemUpdatePayload"
}
}
}
Get epic
Graphql param:
query namespaceWorkItem($fullPath: ID!, $iid: String!) {
workspace: namespace(fullPath: $fullPath) {
id
workItem(iid: $iid) {
...WorkItem
__typename
}
__typename
}
}
fragment WorkItem on WorkItem {
id
iid
archived
title
state
description
confidential
createdAt
closedAt
webUrl
reference(full: true)
createNoteEmail
project {
id
__typename
}
namespace {
id
fullPath
name
__typename
}
author {
...Author
__typename
}
workItemType {
id
name
iconName
__typename
}
userPermissions {
deleteWorkItem
updateWorkItem
adminParentLink
setWorkItemMetadata
createNote
adminWorkItemLink
markNoteAsInternal
__typename
}
widgets {
...WorkItemWidgets
__typename
}
jhIteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
fragment WorkItemWidgets on WorkItemWidget {
type
... on WorkItemWidgetDescription {
description
descriptionHtml
lastEditedAt
lastEditedBy {
name
webPath
__typename
}
taskCompletionStatus {
completedCount
count
__typename
}
__typename
}
... on WorkItemWidgetAssignees {
allowsMultipleAssignees
canInviteMembers
assignees {
nodes {
...User
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetLabels {
allowsScopedLabels
labels {
nodes {
...Label
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetStartAndDueDate {
dueDate
startDate
rollUp
isFixed
__typename
}
... on WorkItemWidgetTimeTracking {
timeEstimate
timelogs {
nodes {
...TimelogFragment
__typename
}
__typename
}
totalTimeSpent
__typename
}
... on WorkItemWidgetWeight {
weight
rolledUpWeight
rolledUpCompletedWeight
widgetDefinition {
editable
rollUp
__typename
}
__typename
}
... on WorkItemWidgetProgress {
progress
updatedAt
__typename
}
... on WorkItemWidgetHierarchy {
hasChildren
hasParent
rolledUpCountsByType {
countsByState {
opened
all
closed
__typename
}
workItemType {
id
name
iconName
__typename
}
__typename
}
parent {
id
iid
title
confidential
webUrl
workItemType {
id
name
iconName
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetIteration {
iteration {
id
title
startDate
dueDate
webUrl
iterationCadence {
id
title
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetMilestone {
milestone {
...MilestoneFragment
__typename
}
__typename
}
... on WorkItemWidgetNotes {
discussionLocked
__typename
}
... on WorkItemWidgetHealthStatus {
healthStatus
rolledUpHealthStatus {
count
healthStatus
__typename
}
__typename
}
... on WorkItemWidgetNotifications {
subscribed
__typename
}
... on WorkItemWidgetCurrentUserTodos {
currentUserTodos(state: pending) {
nodes {
id
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetColor {
color
textColor
__typename
}
... on WorkItemWidgetLinkedItems {
linkedItems {
nodes {
linkId
linkType
__typename
}
__typename
}
__typename
}
... on WorkItemWidgetCrmContacts {
contacts {
nodes {
id
email
firstName
lastName
phone
description
organization {
id
name
description
defaultRate
__typename
}
__typename
}
__typename
}
__typename
}
__typename
}
fragment Label on Label {
id
title
description
color
textColor
__typename
}
fragment User on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
fragment MilestoneFragment on Milestone {
expired
id
title
state
startDate
dueDate
webPath
__typename
}
fragment TimelogFragment on WorkItemTimelog {
__typename
id
timeSpent
user {
id
name
__typename
}
spentAt
note {
id
body
__typename
}
summary
userPermissions {
adminTimelog
__typename
}
}
fragment Author on User {
id
avatarUrl
name
username
webUrl
webPath
__typename
}
Graphql input:
{
"fullPath": "tragedxy",
"iid": "110"
}
Response:
{
"data": {
"workspace": {
"id": "gid://gitlab/Group/72",
"workItem": {
"id": "gid://gitlab/WorkItem/808",
"iid": "110",
"archived": false,
"title": "JH Epic 2025 002",
"state": "OPEN",
"description": "JH Epic 2025 002!!",
"confidential": false,
"createdAt": "2025-03-06T06:11:48Z",
"closedAt": null,
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/epics/110",
"reference": "tragedxy#110",
"createNoteEmail": null,
"project": null,
"namespace": {
"id": "gid://gitlab/Group/72",
"fullPath": "tragedxy",
"name": "Tragedxy",
"__typename": "Namespace"
},
"author": {
"id": "gid://gitlab/User/1",
"avatarUrl": "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon",
"name": "Administrator",
"username": "root",
"webUrl": "http://gdk.test:3000/root",
"webPath": "/root",
"__typename": "UserCore"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"userPermissions": {
"deleteWorkItem": true,
"updateWorkItem": true,
"adminParentLink": true,
"setWorkItemMetadata": true,
"createNote": true,
"adminWorkItemLink": true,
"markNoteAsInternal": true,
"__typename": "WorkItemPermissions"
},
"widgets": [
{
"type": "DESCRIPTION",
"description": "JH Epic 2025 002!!",
"descriptionHtml": "<p data-sourcepos=\"1:1-1:18\" dir=\"auto\">JH Epic 2025 002!!</p>",
"lastEditedAt": null,
"lastEditedBy": null,
"taskCompletionStatus": {
"completedCount": 0,
"count": 0,
"__typename": "TaskCompletionStatus"
},
"__typename": "WorkItemWidgetDescription"
},
{
"type": "HIERARCHY",
"hasChildren": false,
"hasParent": false,
"rolledUpCountsByType": [
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/8",
"name": "Epic",
"iconName": "issue-type-epic",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/1",
"name": "Issue",
"iconName": "issue-type-issue",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
},
{
"countsByState": {
"opened": 0,
"all": 0,
"closed": 0,
"__typename": "WorkItemStateCountsType"
},
"workItemType": {
"id": "gid://gitlab/WorkItems::Type/5",
"name": "Task",
"iconName": "issue-type-task",
"__typename": "WorkItemType"
},
"__typename": "WorkItemTypeCountsByState"
}
],
"parent": null,
"__typename": "WorkItemWidgetHierarchy"
},
{
"type": "LABELS",
"allowsScopedLabels": true,
"labels": {
"nodes": [],
"__typename": "LabelConnection"
},
"__typename": "WorkItemWidgetLabels"
},
{
"type": "NOTES",
"discussionLocked": null,
"__typename": "WorkItemWidgetNotes"
},
{
"type": "START_AND_DUE_DATE",
"dueDate": "2025-01-31",
"startDate": "2025-01-07",
"rollUp": true,
"isFixed": true,
"__typename": "WorkItemWidgetStartAndDueDate"
},
{
"type": "HEALTH_STATUS",
"healthStatus": null,
"rolledUpHealthStatus": [
{
"count": 0,
"healthStatus": "onTrack",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "needsAttention",
"__typename": "WorkItemWidgetHealthStatusCount"
},
{
"count": 0,
"healthStatus": "atRisk",
"__typename": "WorkItemWidgetHealthStatusCount"
}
],
"__typename": "WorkItemWidgetHealthStatus"
},
{
"type": "STATUS",
"__typename": "WorkItemWidgetStatus"
},
{
"type": "NOTIFICATIONS",
"subscribed": true,
"__typename": "WorkItemWidgetNotifications"
},
{
"type": "AWARD_EMOJI",
"__typename": "WorkItemWidgetAwardEmoji"
},
{
"type": "LINKED_ITEMS",
"linkedItems": {
"nodes": [],
"__typename": "LinkedWorkItemTypeConnection"
},
"__typename": "WorkItemWidgetLinkedItems"
},
{
"type": "CURRENT_USER_TODOS",
"currentUserTodos": {
"nodes": [],
"__typename": "TodoConnection"
},
"__typename": "WorkItemWidgetCurrentUserTodos"
},
{
"type": "COLOR",
"color": "#1068bf",
"textColor": "#FFFFFF",
"__typename": "WorkItemWidgetColor"
},
{
"type": "PARTICIPANTS",
"__typename": "WorkItemWidgetParticipants"
},
{
"type": "WEIGHT",
"weight": null,
"rolledUpWeight": null,
"rolledUpCompletedWeight": null,
"widgetDefinition": {
"editable": false,
"rollUp": true,
"__typename": "WorkItemWidgetDefinitionWeight"
},
"__typename": "WorkItemWidgetWeight"
},
{
"type": "TIME_TRACKING",
"timeEstimate": 0,
"timelogs": {
"nodes": [],
"__typename": "WorkItemTimelogConnection"
},
"totalTimeSpent": 0,
"__typename": "WorkItemWidgetTimeTracking"
},
{
"type": "MILESTONE",
"milestone": {
"expired": false,
"id": "gid://gitlab/Milestone/67",
"title": "MST 2025-301",
"state": "active",
"startDate": "2025-03-01",
"dueDate": "2025-03-31",
"webPath": "/groups/tragedxy/-/milestones/5",
"__typename": "Milestone"
},
"__typename": "WorkItemWidgetMilestone"
}
],
"jhIteration": {
"id": "gid://gitlab/Iteration/83422",
"title": null,
"startDate": "2025-02-17",
"dueDate": "2025-03-16",
"webUrl": "http://gdk.test:3000/groups/tragedxy/-/iterations/83422",
"iterationCadence": {
"id": "gid://gitlab/Iterations::Cadence/8004",
"title": "2025-Q1",
"__typename": "IterationCadence"
},
"__typename": "Iteration"
},
"__typename": "WorkItem"
},
"__typename": "Namespace"
}
}
}
合并请求类型
Enhancement
合并请求描述
- 重构了 JH 工作项的创建和更新逻辑,以支持新的工作项属性。
- 添加了对里程碑和迭代小部件的支持,并重写了相关方法。
- 添加了新的服务模块
JH::WorkItems::CreateService
和JH::WorkItems::UpdateService
以处理 JH 扩展。 - 添加了测试用例以验证 JH 工作项的创建和更新逻辑。
变更概览
相关文件 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
功能增强 | 8 files
|
||||||||||||||||
测试 |