Dynamic Forms

Use the Dynamic Forms feature to simplify the process of adding variables to your ScriptRunner Groovy scripts. Dynamic Forms allows you to create complex scripts with flexible variables that can be shared with multiple users, allowing one script to be used for various use cases.

Inline scripts are often copied and pasted, with minor changes made for different use cases. This approach requires maintenance for each usage of the script. Using Dynamic Forms, create flexible scripts with annotated variables that can be stored as files, reducing maintenance requirements while allowing for script customization.

Annotate your variables to have them appear as form fields when a user edits a script. These annotations allow variable values within a script to be changed easily by those with limited code familiarity.

Dynamic forms annotations are available anywhere you can enter code in ScriptRunner, including the Script Console, Conditions, Validators, Post Functions, Behaviours, and many more.

For example, as a power user, you have created a script to delete issues within a project with a specific assignee. This script is used across multiple locations, varying by one variable (User) for each use case. Instead of hardcoding the User variable, you can now use a dynamic form annotation, meaning the user can be changed without needing to re-write the script. As well as being able to edit the script quickly, you can maintain the code in one centralized location. The dynamic form annotation shows the User variable as a form field:

The above example uses the following code:

groovy
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.search.SearchProvider import com.atlassian.jira.jql.parser.JqlQueryParser import com.atlassian.jira.user.ApplicationUser import com.atlassian.jira.web.bean.PagerFilter import com.onresolve.scriptrunner.parameters.annotation.UserPicker @UserPicker(label = "Assignee", description = "Issues with this assignee will be permanently deleted") ApplicationUser user // issues returned from that JQL will get deleted final String searchQuery = "assignee = $user.name" def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser) def searchProvider = ComponentAccessor.getComponent(SearchProvider) def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser def issueService = ComponentAccessor.issueService def query = jqlQueryParser.parseQuery(searchQuery) def searchResults = searchProvider.search(query, loggedInUser, PagerFilter.unlimitedFilter) searchResults.getIssues().each { issue -> def deleteValidationResult = issueService.validateDelete(loggedInUser, issue.id) assert deleteValidationResult.isValid(): deleteValidationResult.errorCollection def deleteResult = issueService.delete(loggedInUser, deleteValidationResult) assert deleteResult }


The following dynamic form field types are available:

NameDescriptionTarget Type

User Picker

Field allowing user selection.

com.atlassian.jira.user.ApplicationUser

Field Picker

Field to select any system or custom field.

com.atlassian.jira.issue.fields.Field

Short Text

Field allowing a short text input.

String

Select List

Single-select list field.

String

Checkbox

A checkbox field.

Boolean

Project Picker

Field allowing project selection.

com.atlassian.jira.project.Project

Priority PickerField allowing priority selection.com.atlassian.jira.issue.priority.Priority
Issue Type PickerField allowing issue type selection.com.atlassian.jira.issue.issuetype.IssueType
Issue Link Type PickerField allowing issue link type selection.com.atlassian.jira.issue.link.IssueLinkType
Project Role PickerField allowing project role selection.com.atlassian.jira.security.roles.ProjectRole
Group PickerField allowing group selection.com.atlassian.crowd.embedded.api.Group
Saved Filter PickerField allowing saved filter selection.com.atlassian.jira.issue.search.SearchRequest
Issue Status PickerField allowing status selection.com.atlassian.jira.issue.status.Status

We are in the process of adding more dynamic form field types.

Create a Dynamic Form

  1. Click the Cog in the top ribbon, and open the Add-ons page.

  2. Select Script Console under ScriptRunner.

  3. Write your new script in the Script field, annotating the variables you want users to provide (see the Examples section below). Annotating variables allows them to be edited depending on requirements when running the script. These variables show as editable fields above the Script Console.

Transforming an Existing Inline Script

To enable sharing of annotated scripts, all inline scripts must be saved as files.

  1. Navigate to your existing inline script, and add in required annotations.

  2. Copy the script.

  3. Use the Script Editor to open your Scripts Root folder.

  4. Select the folder in which you want to save the script, and click the Create New File icon.

  5. Enter a file name in the Add New Groovy File/Add New Groovy Folder window.

  6. Click Add.

  7. Paste your inline script into the file, and click Save. This script is now available as a file and can be shared with multiple Jira users on the same instance.

Annotations

User Picker

Add a username picker field into your script.

groovy
import com.atlassian.jira.user.ApplicationUser import com.onresolve.scriptrunner.parameters.annotation.* @UserPicker(label = "User", description = "Select a user") ApplicationUser user

Field Picker

Add a field picker into your script. The field picker lets you pick from any fields (system or custom).

groovy
import com.atlassian.jira.issue.fields.Field import com.onresolve.scriptrunner.parameters.annotation.* @FieldPicker(label = "Field", description = "Select a field") Field field

Short Text

Add a short text field to a script.

groovy
import com.onresolve.scriptrunner.parameters.annotation.* @ShortTextInput(label = "Text input label", description = "Text Input Description") String shortTextInputValue

Select List

Add a single-select list with configurable options.

groovy
import com.onresolve.scriptrunner.parameters.annotation.* import com.onresolve.scriptrunner.parameters.annotation.meta.* @Select( label = "Color", description = "Select color", options = [ @Option(label = "Green", value = "green"), @Option(label = "Blue", value = "blue"), ] ) String value

Checkbox

Add a checkbox to a script.

groovy
import com.onresolve.scriptrunner.parameters.annotation.* @Checkbox(description = "Check the checkbox to true or unselect to false", label = "Checkbox label") boolean isChecked

Project Picker

Add a project picker to a script.

groovy
import com.atlassian.jira.project.Project import com.onresolve.scriptrunner.parameters.annotation.ProjectPicker @ProjectPicker(label = 'Project', description = 'Pick a project') Project project

Priority Picker

Add a priority picker to a script.

groovy
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 priority

Issue Type Picker

Add an issue type picker to a script.


groovy
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 issueType

Issue Link Type Picker

Add an issue link type picker to a script.

groovy
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

Project Role Picker

Add a project role picker to a script.

groovy
import com.atlassian.jira.security.roles.ProjectRole import com.onresolve.scriptrunner.parameters.annotation.ProjectRolePicker @ProjectRolePicker(label = 'Project role', description = 'Project role picker') ProjectRole projectRole

Group Picker

Add a group Picker to a script.

groovy
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 group

Saved Filter Picker

Add a saved filter to a script.

groovy
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 searchRequest

Issue Status Picker

Add a status to a script.

groovy
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 status

All Fields

Use several annotators to create a dynamic form.

groovy
import com.atlassian.crowd.embedded.api.Group import com.atlassian.jira.issue.fields.Field import com.atlassian.jira.issue.status.Status import com.atlassian.jira.project.Project import com.atlassian.jira.issue.issuetype.IssueType import com.atlassian.jira.issue.link.IssueLinkType import com.atlassian.jira.issue.priority.Priority import com.atlassian.jira.security.roles.ProjectRole import com.atlassian.jira.issue.search.SearchRequest import com.atlassian.jira.user.ApplicationUser import com.onresolve.scriptrunner.parameters.annotation.Checkbox import com.onresolve.scriptrunner.parameters.annotation.FieldPicker import com.onresolve.scriptrunner.parameters.annotation.ProjectPicker import com.onresolve.scriptrunner.parameters.annotation.IssueTypePicker import com.onresolve.scriptrunner.parameters.annotation.IssueLinkTypePicker import com.onresolve.scriptrunner.parameters.annotation.PriorityPicker import com.onresolve.scriptrunner.parameters.annotation.ProjectRolePicker import com.onresolve.scriptrunner.parameters.annotation.SavedFilterPicker import com.onresolve.scriptrunner.parameters.annotation.ShortTextInput import com.onresolve.scriptrunner.parameters.annotation.GroupPicker import com.onresolve.scriptrunner.parameters.annotation.IssueStatusPicker import com.onresolve.scriptrunner.parameters.annotation.UserPicker import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate import groovy.json.JsonBuilder import groovy.transform.BaseScript import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.core.Response @FieldPicker(label = "FieldPickerLabel", description = "FieldPickerDescription") Field field @ShortTextInput(label = "Dynamic text input label", description = "Dynamic Text Input Description") String shortTextInput @Checkbox(label = "Dynamic Checkbox label", description = "Check the checkbox to true or unselect to false") boolean selected @UserPicker(label = "Select a User", description = "Select a user on the UserPicker") ApplicationUser user @ProjectPicker(label = 'Select a Project', description = 'Select a project on the ProjectPicker') Project project @PriorityPicker(label = 'Priority', description = 'Pick a priority', placeholder = 'Pick a priority') Priority priority @IssueTypePicker(label = 'Issue type', description = 'Pick an issue type', placeholder = 'Select issue type') IssueType issueType @IssueLinkTypePicker(label = 'Issue link type', description = 'Pick an issue link type', placeholder = 'Pick an issue link type') IssueLinkType issueLinkType @ProjectRolePicker(label = 'Project role', description = 'Project a role picker', placeholder = 'Pick a project role') ProjectRole projectRole @GroupPicker(label = 'Group', description = 'Pick a group', placeholder = 'Pick a group') Group group @SavedFilterPicker(label = 'Saved Filter', description = 'Pick a saved filter', placeholder="Pick a saved filter") SearchRequest savedFilter @IssueStatusPicker(label = 'Status', description = 'Pick a status', placeholder = 'Pick a status') Status status @BaseScript CustomEndpointDelegate delegate doSomething(httpMethod: "GET", groups: ["jira-administrators"]) { MultivaluedMap queryParams, String body -> return Response.ok(new JsonBuilder([ user: user.name, selected: selected, fieldPicker: field.getName(), shortTextInput: shortTextInput, projectPicker: project?.name, priority: priority?.name, issueType: issueType?.name, issueLinkType: issueLinkType?.name, projectRole: projectRole?.name, group: group?.name, savedFilter: savedFilter?.name, status: status?.name, ] ).toString()).build() }
On this page