Dynamic Forms
Use the Dynamic Forms feature to simplify the process of adding variables to your ScriptRunner Groovy scripts.
With Dynamic Forms, you can annotate your variables in a script so they appear as selectable form fields. You can then save that script as a file to be shared with multiple users, allowing one script to be used for various use cases.
Why is the Dynamic Forms feature useful?
Inline scripts are often copied and pasted, with minor changes made for different use cases, which requires maintenance for each script usage. Using Dynamic Forms, you can create flexible scripts with annotated variables that can be stored as files, reducing maintenance requirements while allowing for script customization. Additionally, these annotations allow variable values within a script to be changed easily by those with limited code familiarity.
Where can you use the Dynamic Forms feature?
Dynamic Forms are everywhere! You can use them on Listeners, Jobs, and just about everywhere you can write code.
Available dynamic form field types
The following dynamic form field types are available:
Creating a dynamic form
While the Dynamic Forms feature can be used however you find most useful, there are three main steps in creating a dynamic form that can be used across multiple features by multiple users:
- Create the dynamic form in the Script Console to make sure it works as expected.
- Save the dynamic form as a file.
- Use the saved file in a Job, Listener or other ScriptRunner feature.
The above steps are detailed in the tasks that follow.
Create a dynamic form
Save the dynamic form as a file
Use the dynamic form file elsewhere
Transforming an existing inline script into a dynamic form
To enable sharing of annotated scripts, all inline scripts must be saved as files.
Using HTML to format descriptions
You can use HTML to modify the appearance of descriptions when you create a dynamic form. For example, if we take the Create a dynamic form example above and add HTML to the description:
import com.atlassian.jira.user.ApplicationUser
import com.onresolve.scriptrunner.parameters.annotation.UserPicker
@UserPicker(label = "Assignee", description = "<h3><b>Big: Issues with this assignee</b></h3>Small: will be permanently deleted")
ApplicationUser user
// issues returned from that JQL will get deleted
final String searchQuery = "assignee = $user.name"
Issues.search(searchQuery).each { issue ->
issue.delete()
}The HTML changes the appearance as follows:
Annotations
User picker
Add a user picker field into your script.
import com.atlassian.jira.user.ApplicationUser
import com.onresolve.scriptrunner.parameters.annotation.*
@UserPicker(label = "User", description = "Select a user")
ApplicationUser userUser multi-pickers are also supported.
import com.atlassian.jira.user.ApplicationUser
import com.onresolve.scriptrunner.parameters.annotation.*
@UserPicker(label = "Users", description = "Select users", multiple = true)
List<ApplicationUser> usersField picker
Add a field picker into your script. The field picker lets you pick from any fields (system or custom).
import com.atlassian.jira.issue.fields.Field
import com.onresolve.scriptrunner.parameters.annotation.*
@FieldPicker(label = "Field", description = "Select a field")
Field fieldField multi-pickers are also supported.
import com.atlassian.jira.issue.fields.Field
import com.onresolve.scriptrunner.parameters.annotation.*
@FieldPicker(label = "Fields", description = "Select fields", multiple = true)
List<Field> fieldsShort text
Add a short text field to a script.
import com.onresolve.scriptrunner.parameters.annotation.*
@ShortTextInput(label = "Summary", description = "Enter a short issue summary")
String issueSummaryTextInputNumber
Add a number field to a script.
import com.onresolve.scriptrunner.parameters.annotation.NumberInput
@NumberInput(label = 'Number of Approvals', description = 'How many approvals should be required')
Integer requiredApprovalsSelect list
Add a single-select list with configurable options.
import com.onresolve.scriptrunner.parameters.annotation.Select
import com.onresolve.scriptrunner.parameters.annotation.meta.Option
@Select(
label = "Color",
description = "Select color",
placeholder = 'Just pick any color',
options = [
@Option(label = "Green", value = "green"),
@Option(label = "Blue", value = "blue"),
]
)
String valueMulti-select lists are also supported.
import com.onresolve.scriptrunner.parameters.annotation.Select
import com.onresolve.scriptrunner.parameters.annotation.meta.Option
@Select(
label = "Colors",
description = "Select colors",
options = [
@Option(label = "Green", value = "green"),
@Option(label = "Blue", value = "blue"),
@Option(label = "Red", value = "red"),
],
multiple = true
)
List<String> valuesUsing optionsGenerator in a select list
If you cannot find an annotation that is suitable for your purpose, you can provide an optionsGenerator closure when using @Select to generate a list of custom options. For example:
import com.onresolve.scriptrunner.parameters.annotation.Select
@Select(
label = "Color",
description = "Select color",
optionsGenerator = {
[
['yellow', 'Yellow'],
['red', 'Red'],
]
}
)
String value- The first element must be the option value (that is, what is injected into your variable).
- The second element must be the display value.
The closure code must be completely self-contained, apart from import declarations. Therefore, you cannot use variables or methods declared outside the closure.
We recommend you keep the contents of these closures short and simple.
The following is a Jira example, using optionsGenerator that lists all projects in a specific project category:
import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.parameters.annotation.Select
@Select(
label = "Project",
description = "Select the Space project",
optionsGenerator = {
def projectManager = ComponentAccessor.projectManager
def category = projectManager.getProjectCategoryObjectByName('Space Projects')
projectManager.getProjectObjectsFromProjectCategory(category.id).collect { project ->
[project.key, project.name]
}
}
)
String valueCheckbox
Add a checkbox to a script.
import com.onresolve.scriptrunner.parameters.annotation.*
@Checkbox(label = "Clone project", description = "Select the checkbox to clone project")
Boolean projectShouldBeClonedProject picker
Add a project picker to a script.
import com.atlassian.jira.project.Project
import com.onresolve.scriptrunner.parameters.annotation.ProjectPicker
@ProjectPicker(
label = 'Project', description = 'Pick a project', placeholder = 'Pick a project', includeArchived = false
)
Project projectProject multi-pickers are also supported.
import com.atlassian.jira.project.Project
import com.onresolve.scriptrunner.parameters.annotation.ProjectPicker
@ProjectPicker(
label = 'Projects', description = 'Pick projects', placeholder = 'Pick projects', includeArchived = false,
multiple = true
)
List<Project> projectsPriority picker
Add a priority picker to a script.
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.parameters.annotation.PriorityPicker
@PriorityPicker(label = 'Priority', description = 'Pick a priority', placeholder = 'Pick a priority')
Priority priorityPriority multi-pickers are also supported.
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.parameters.annotation.PriorityPicker
@PriorityPicker(
label = 'Priorities', description = 'Pick priorities', placeholder = 'Pick priorities', multiple = true
)
List<Priority> prioritiesIssue type picker
Add an issue type picker to a script.
import com.atlassian.jira.issue.issuetype.IssueType
import com.onresolve.scriptrunner.parameters.annotation.IssueTypePicker
@IssueTypePicker(label = 'Issue type', description = 'Pick an issue type', placeholder = 'Select issue type')
IssueType issueTypeIssue type multi-pickers are also supported.
import com.atlassian.jira.issue.issuetype.IssueType
import com.onresolve.scriptrunner.parameters.annotation.IssueTypePicker
@IssueTypePicker(
label = 'Issue type', description = 'Pick issue types', placeholder = 'Select issue types',
multiple = true
)
List<IssueType> issueTypesIssue link type picker
Add an issue link type picker to a script.
import com.atlassian.jira.issue.link.IssueLinkType
import com.onresolve.scriptrunner.parameters.annotation.IssueLinkTypePicker
@IssueLinkTypePicker(label = 'Issue link type', description = 'Pick an issue link type', placeholder = 'Pick an issue link type')
IssueLinkType issueLinkType Issue link type multi-pickers are also supported.
import com.atlassian.jira.issue.link.IssueLinkType
import com.onresolve.scriptrunner.parameters.annotation.IssueLinkTypePicker
@IssueLinkTypePicker(
label = 'Issue link types', description = 'Pick issue link types', placeholder = 'Pick issue link types',
multiple = true
)
List<IssueLinkType> issueLinkTypes Project role picker
Add a project role picker to a script.
import com.atlassian.jira.security.roles.ProjectRole
import com.onresolve.scriptrunner.parameters.annotation.ProjectRolePicker
@ProjectRolePicker(label = 'Project role', description = 'Project role picker')
ProjectRole projectRoleProject role multi pickers are also supported.
import com.atlassian.jira.security.roles.ProjectRole
import com.onresolve.scriptrunner.parameters.annotation.ProjectRolePicker
@ProjectRolePicker(label = 'Project roles', description = 'Project role picker', multiple = true)
List<ProjectRole> projectRolesGroup picker
Add a group Picker to a script.
import com.atlassian.crowd.embedded.api.Group
import com.onresolve.scriptrunner.parameters.annotation.GroupPicker
@GroupPicker(label = 'Group', description = 'Pick a group', placeholder = 'Pick a group')
Group groupGroup multi-pickers are also supported.
import com.atlassian.crowd.embedded.api.Group
import com.onresolve.scriptrunner.parameters.annotation.GroupPicker
@GroupPicker(label = 'Groups', description = 'Pick groups', placeholder = 'Pick groups', multiple = true)
List<Group> groupsSaved filter picker
Add a saved filter to a script.
import com.atlassian.jira.issue.search.SearchRequest
import com.onresolve.scriptrunner.parameters.annotation.SavedFilterPicker
@SavedFilterPicker(label = "Saved Filter", description = "Pick a saved filter", placeholder = "Pick a saved filter")
SearchRequest searchRequestSaved filter multi-pickers are also supported.
import com.atlassian.jira.issue.search.SearchRequest
import com.onresolve.scriptrunner.parameters.annotation.SavedFilterPicker
@SavedFilterPicker(
label = "Saved Filters", description = "Pick saved filters", placeholder = "Pick saved filters",
multiple = true
)
List<SearchRequest> searchRequestsIssue status picker
Add a status to a script.
import com.atlassian.jira.issue.status.Status
import com.onresolve.scriptrunner.parameters.annotation.IssueStatusPicker
@IssueStatusPicker(label = 'Status', description = 'Pick a status', placeholder = 'Pick a status')
Status statusIssue status multi pickers are also supported.
import com.atlassian.jira.issue.status.Status
import com.onresolve.scriptrunner.parameters.annotation.IssueStatusPicker
@IssueStatusPicker(
label = 'Statuses', description = 'Pick statuses', placeholder = 'Pick statuses', multiple = true
)
List<Status> statusesCustom field picker
Add a custom field picker to a script.
import com.atlassian.jira.issue.fields.CustomField
import com.onresolve.scriptrunner.parameters.annotation.CustomFieldPicker
@CustomFieldPicker(label = 'Custom Field', description = 'Pick a custom field', placeholder='Select custom field')
CustomField customFieldCustom field multi-pickers are also supported.
import com.atlassian.jira.issue.fields.CustomField
import com.onresolve.scriptrunner.parameters.annotation.CustomFieldPicker
@CustomFieldPicker(
label = 'Custom Fields', description = 'Pick custom fields', placeholder='Select custom fields',
multiple = true
)
List<CustomField> customFieldsResolution picker
Add a resolution to a script.
import com.atlassian.jira.issue.resolution.Resolution
import com.onresolve.scriptrunner.parameters.annotation.ResolutionPicker
@ResolutionPicker(label = 'Resolution', description = 'Pick a resolution', placeholder = 'Pick a resolution')
Resolution resolutionResolution multi-pickers are also supported.
import com.atlassian.jira.issue.resolution.Resolution
import com.onresolve.scriptrunner.parameters.annotation.ResolutionPicker
@ResolutionPicker(
label = 'Resolutions', description = 'Pick resolutions', placeholder = 'Pick resolutions',
multiple = true
)
List<Resolution> resolutionsVersion picker
Add a version to a script.
import com.atlassian.jira.project.version.Version
import com.onresolve.scriptrunner.parameters.annotation.VersionPicker
@VersionPicker(
label = 'Version', description = 'Pick a version',
projectPlaceholder = 'Pick a project', placeholder = 'Pick a version'
)
Version versionVersion multi-pickers are also supported.
import com.atlassian.jira.project.version.Version
import com.onresolve.scriptrunner.parameters.annotation.VersionPicker
@VersionPicker(
label = 'Versions', description = 'Pick versions',
projectPlaceholder = 'Pick a project', placeholder = 'Pick versions', multiple = true
)
List<Version> versionsComponent picker
Add a component to a script.
import com.atlassian.jira.bc.project.component.ProjectComponent
import com.onresolve.scriptrunner.parameters.annotation.ComponentPicker
@ComponentPicker(
label = 'Component', description = 'Pick a component',
projectPlaceholder = 'Pick a project', placeholder = 'Pick a component'
)
ProjectComponent componentComponent multi-pickers are also supported.
import com.atlassian.jira.bc.project.component.ProjectComponent
import com.onresolve.scriptrunner.parameters.annotation.ComponentPicker
@ComponentPicker(
label = 'Components', description = 'Pick components',
projectPlaceholder = 'Pick a project', placeholder = 'Pick components', multiple = true
)
List<ProjectComponent> componentsPermission scheme picker
Add a permission scheme to a script.
import com.onresolve.scriptrunner.parameters.annotation.PermissionSchemePicker
import com.atlassian.jira.scheme.Scheme
@PermissionSchemePicker(label = 'Permission scheme', description = 'Pick a permission scheme', multiple = false)
Scheme schemePermission scheme multi-pickers are also supported.
import com.onresolve.scriptrunner.parameters.annotation.PermissionSchemePicker
import com.atlassian.jira.scheme.Scheme
@PermissionSchemePicker(label = 'Permission schemes', description = 'Pick permission schemes', multiple = true)
List<Scheme> schemesWorkflow scheme picker
Add a workflow scheme to a script.
import com.onresolve.scriptrunner.parameters.annotation.WorkflowSchemePicker
import com.atlassian.jira.scheme.Scheme
@WorkflowSchemePicker(label = 'Workflow scheme', description = 'Pick a workflow scheme', multiple = false)
Scheme schemeWorkflow scheme multi-pickers are also supported.
import com.onresolve.scriptrunner.parameters.annotation.WorkflowSchemePicker
import com.atlassian.jira.scheme.Scheme
@WorkflowSchemePicker(label = 'Workflow schemes', description = 'Pick workflow schemes', multiple = true)
List<Scheme> schemes