Skip to content

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::CreateServiceJH::WorkItems::UpdateService 以处理 JH 扩展。
  • 添加了测试用例以验证 JH 工作项的创建和更新逻辑。

变更概览

相关文件
功能增强
8 files
widgetable.rb
添加 JH 扩展支持到 WorkItems::Widgetable                                               

app/graphql/mutations/concerns/mutations/work_items/widgetable.rb

  • 添加了 Mutations::WorkItems::Widgetable.prepend_mod 以支持 JH 扩展。
+3/-0     
create.rb
重构 JH 工作项创建逻辑                                                                                       

jh/app/graphql/jh/mutations/work_items/create.rb

Epics::Create 模块重命名为 WorkItems::Create
修改了 resolve 方法以支持新的工作项属性。
+5/-5     
update.rb
重构 JH 工作项更新逻辑                                                                                       

jh/app/graphql/jh/mutations/work_items/update.rb

Epics::Update 模块重命名为 WorkItems::Update
修改了 resolve 方法以支持新的工作项属性。
+5/-5     
widgetable.rb
添加 JH 工作项小部件支持                                                                                     

jh/app/graphql/mutations/concerns/jh/mutations/work_items/widgetable.rb

添加了 JH::Mutations::WorkItems::Widgetable 模块。
定义了 JH_ALLOWED_WIDGET_KEYS 并重写了 extract_widget_params! 方法。
+35/-0   
scoped_work_items_arguments.rb
重构 JH 工作项参数验证逻辑                                                                                   

jh/app/graphql/mutations/work_items/scoped_work_items_arguments.rb

Epics::ScopedEpicArguments 重命名为 WorkItems::ScopedWorkItemsArguments
修改了 validate_milestonevalidate_iteration 方法以支持新的工作项属性。
+12/-20 
sync_as_epic_extends.rb
重构 JH 工作项同步逻辑                                                                                       

jh/app/services/concerns/work_items/sync_as_epic_extends.rb

JH::IssuableBaseService 重命名为 WorkItems::SyncAsEpicExtends
修改了 initialize 方法以支持新的工作项属性。
添加了 attach_iteration_to 方法。
+23/-39 
create_service.rb
添加 JH 工作项创建服务                                                                                       

jh/app/services/jh/work_items/create_service.rb

添加了 JH::WorkItems::CreateService 模块。
重写了 transaction_create 方法以支持 JH 扩展。
+24/-0   
update_service.rb
添加 JH 工作项更新服务                                                                                       

jh/app/services/jh/work_items/update_service.rb

  • 添加了 JH::WorkItems::UpdateService 模块。
  • 重写了 update 方法以支持 JH 扩展。
+24/-0   
测试
2 files
create_spec.rb
添加 JH 工作项创建测试                                                                                       

jh/spec/requests/api/graphql/mutations/work_items/create_spec.rb

  • 添加了测试用例以验证 JH 工作项创建时的里程碑和迭代小部件支持。
+176/-0 
update_spec.rb
添加 JH 工作项更新测试                                                                                       

jh/spec/requests/api/graphql/mutations/work_items/update_spec.rb

  • 添加了测试用例以验证 JH 工作项更新时的里程碑和迭代小部件支持。
+270/-0 
xfyuan 编辑于

合并请求报告

加载中