Sub-task Default Field

Here we describe how to set up default fields for the Create sub-tasks action, where the default values are derived from the parent issue fields.

The key to this is getting the parent issue ID via the parentIssueId form field. Once you have that you can load that issue, get the fields, and set them in the Create Issue dialog.

You should use the behaviour initialiser script section to set the default values within your form.

How to get the parent Issue in behaviours

The following sample code demonstrates how to:

  • Get the parent issue object using the value of the parentIssueId form field.
  • Copy the parent issue's summary to the sub-task summary field.

import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.jira.groovy.user.FieldBehaviours
import groovy.transform.BaseScript

import static com.atlassian.jira.issue.IssueFieldConstants.SUMMARY

@BaseScript FieldBehaviours fieldBehaviours

def parent = getFieldById("parentIssueId")
def parentIssueId = parent.getFormValue() as Long
def summary = getFieldById(SUMMARY)

if (!parentIssueId || underlyingIssue) {
    // this is not a subtask, or issue already exists, so don't set default values
    return
}

def issueManager = ComponentAccessor.getIssueManager()
def parentIssue = issueManager.getIssueObject(parentIssueId)

summary.setFormValue(parentIssue.summary)

How to copy common system fields and custom fields

The following sample code demonstrates how to:

  • Get the parent issue object using the value of the parentIssueId field.
  • Copy common system fields values to the sub-task Create Issue dialog form.
  • Copy custom field values to the sub-task Create Issue dialog form.

This sample code demonstrates copying all fields from the parent to the new sub-task. In practice, you will want to select only the system and custom fields you need, by editing this example.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.datetime.DateTimeFormatterFactory
import com.atlassian.jira.datetime.DateTimeStyle
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.fields.CustomField
import com.onresolve.jira.groovy.user.FieldBehaviours
import groovy.transform.BaseScript

import java.sql.Timestamp

import static com.atlassian.jira.issue.IssueFieldConstants.AFFECTED_VERSIONS
import static com.atlassian.jira.issue.IssueFieldConstants.ASSIGNEE
import static com.atlassian.jira.issue.IssueFieldConstants.COMPONENTS
import static com.atlassian.jira.issue.IssueFieldConstants.DESCRIPTION
import static com.atlassian.jira.issue.IssueFieldConstants.DUE_DATE
import static com.atlassian.jira.issue.IssueFieldConstants.ENVIRONMENT
import static com.atlassian.jira.issue.IssueFieldConstants.FIX_FOR_VERSIONS
import static com.atlassian.jira.issue.IssueFieldConstants.LABELS
import static com.atlassian.jira.issue.IssueFieldConstants.PRIORITY
import static com.atlassian.jira.issue.IssueFieldConstants.SUMMARY

@BaseScript FieldBehaviours fieldBehaviours

def parent = getFieldById("parentIssueId")
def parentIssueId = parent.getFormValue() as Long

if (!parentIssueId || underlyingIssue) {
    // this is not a subtask, or issue already exists, so don't set default values
    return
}

def issueManager = ComponentAccessor.getIssueManager()
def parentIssue = issueManager.getIssueObject(parentIssueId)
def customFieldManager = ComponentAccessor.getCustomFieldManager()

// REMOVE OR MODIFY THE SETTING OF THESE FIELDS AS NECESSARY
getFieldById(SUMMARY).setFormValue(parentIssue.summary)
getFieldById(PRIORITY).setFormValue(parentIssue.priority.id)

def dateTimeFormatterFactory = ComponentAccessor.getComponent(DateTimeFormatterFactory)
def defaultLocaleFormatter = dateTimeFormatterFactory.formatter().withStyle(DateTimeStyle.DATE).withDefaultLocale()
getFieldById(DUE_DATE).setFormValue(defaultLocaleFormatter.format(parentIssue.getDueDate()))

getFieldById(COMPONENTS).setFormValue(parentIssue.components*.id)
getFieldById(AFFECTED_VERSIONS).setFormValue(parentIssue.affectedVersions*.id)
getFieldById(FIX_FOR_VERSIONS).setFormValue(parentIssue.fixVersions*.id)
getFieldById(ASSIGNEE).setFormValue(parentIssue.assignee?.name)
getFieldById(ENVIRONMENT).setFormValue(parentIssue.environment)
getFieldById(DESCRIPTION).setFormValue(parentIssue.description)
getFieldById(LABELS).setFormValue(parentIssue.labels*.label)

// IF YOU DON'T WANT CUSTOM FIELDS COPIED REMOVE EVERYTHING BELOW HERE
// IF YOU ONLY WANT SOME FIELDS INHERITED ADD THEM TO THE LIST BELOW, OR LEAVE EMPTY FOR ALL
// eg ['Name of first custom field', 'Name of second custom field']
List copyCustomFields = []

List<CustomField> parentFields = customFieldManager.getCustomFieldObjects(parentIssue)

parentFields.each { cf ->
    if (copyCustomFields && !copyCustomFields.contains(cf.name)) {
        return
    }

    def parentValue = cf.getValue(parentIssue)

    if (!parentValue) {
        return
    }

    if (parentValue instanceof Timestamp) {
        getFieldById(cf.id).setFormValue(defaultLocaleFormatter.format(parentValue))
    } else if (parentValue instanceof Option) {
        getFieldById(cf.id).setFormValue(parentValue.optionId)
    } else if (parentValue instanceof List<Option>) {
        parentValue = parentValue as List<Option> //This cast is just to placate the static type checker
        getFieldById(cf.id).setFormValue(parentValue.collect { it.optionId })
    } else {
        getFieldById(cf.id).setFormValue(parentValue)
    }
}

On this page