Custom Picker
Use a Custom Picker field to set up a field that allows users to pick values from a list. It is similar to the Database, LDAP, and Issue Picker script fields, but it is not specialized for any particular case.
For example, you can set up a custom picker to pick a Jira object such as a Version, User, or Component when you want custom selection criteria that are not available when using the native field types. Or you may want to utilize it when picking from a list that can be searched using a REST API.
At a minimum, you need to provide code for handling the following:
- Returning a list of objects when the user opens the drop-down, and when they type text for searching.
- Converting from the "object" to an option in the drop-down. This is where you select the object's unique ID that is stored in the Jira database.
- Given the ID that is stored, convert back to the "object".
- Rendering the "object".
The "object" in the above example differs depending on what type of structure this field represents. In the case of a version picker, it will be a com.atlassian.jira.project.version.Version. For a user, it should be a com.atlassian.jira.user.ApplicationUser etc. When picking from a rest resource, it will generally be a Map.
Example
Country Picker
In this example, users can select a country from a REST resource that provides geographical data.
We use https://restcountries.com/ as our example resource for this scenario.
Before starting the implementation of a REST resource picker, the following needs to be established:
- That we can search by name. For example, https://restcountries.com/v2/name/united.
- That we can get the first number of records for when the user opens the drop-down and does not type anything. In this case, we can use https://restcountries.com/v2/all.
- That each object has a unique identifier, and that we can look up the object by this unique identifier. For example, countries have a unique 3-character ID, e.g. GBR, and we can get this country from the ID. For example, https://restcountries.com/v2/alpha/GBR to retrieve the United Kingdom.
Once we have tested all the above in the browser, we can start coding.
The following example can be accessed from the Snippets menu under the configuration script.
We recommend you start with one of the working examples and adjust it before implementing your own.
https://restcountries.com is not related to Adaptavist and we cannot guarantee its uptime. This example is just for instructive and testing purposes. In practice, it does not make sense to use this as a country picker, as ~200 countries could be handled by a Select List. Choosing from a REST resource is most useful when the number of selections is too large for a select list, or subject to change, or have multiple attributes that you might want to display.
Caching
Retrieving information from REST resources can be expensive. Each time the issue is viewed, the code making the REST request is called in order to get the item; hence it is advisable to cache responses.
As always, with caching, there is a balance between the cache size (limiting the memory consumed by the cached objects), the staleness of objects in the cache, and the cost of reloading new ones.
Because of all these variables, caching is left to the script author. In general, we recommend using either com.google.common.cache.CacheBuilder (Google Guava), or com.atlassian.cache.CacheManager, which is a wrapper over the Guava cache.
In the case of the country picker example above, we could set the size to around 250, as there are only ~200 countries in the world. Although it happens, it's not common for countries to be deleted or for them to change names, so we don't need to worry about expiring countries from the cache.
Cache Loader Method
The example below is similar to the previous country picker example, except that fetching from the REST resource has been moved from getItemFromId
into the cache loader method.
The other notable change is that, because Guava cache does not allow null keys or values, the actual value is wrapped in an Optional. This avoids failures if a country has been deleted. Using the web UI, it is not possible for a user to enter a country code that does not exist; however, they could do it using Jira's REST API.
In this case, it would make sense to cache all the countries and search in memory; however, in most cases, it's not practical to load all possible options.
Disabled vs. Non-Existent
Some thought must be given to what constitutes a valid selection in a custom picker.
In this user picker example, we only want to allow users who are members of either of the jira-administrators or jira-system-administrators groups.
If an administrator is selected in the picker, and then at a later date removed from the administrator group, that option is disabled in the picker list. This should make that option "disabled." In this case, the issue can be edited with this disabled value without errors, but new issues cannot be created with this disabled value.
In the case of a selected user being "deleted," getItemFromId
should return null
.
The following example introduces a final closure validate
. This checks the "object" matches the required selection criteria.
Note that search
should only return items that are valid. In this case, we use UserSearchService to filter on only users in those groups.
Further Examples
The following additional examples are available in the Snippets drop-down under the Configuration Script section.
Version Picker
This example allows users to pick a non-archived Jira version across projects. This a further example of using validate
to ensure only the selection of a non-archived Version.
Additionally, we customize the display using a lozenge to show the Version Status:
GitHub Repository Picker
This uses the GitHub REST API to allow the selection of a repository in the Adaptavist organization. This is not a practical example due to the Rate Limiting on the GitHub API. Even when authenticated, you are only allowed a minimal number of calls to the search resource.
Customizing the Displayed Value
As with the Issue Picker, HTML can be provided for each selected item in a multi-picker.
As well as renderItemViewHtml,
renderItemColumnViewHtml
can be used to display an abbreviated value when used in the Issue Navigator, along with renderItemTextOnlyValue
for the plain text value which is used in History Tab, email notifications and CSV exports.
For rendering multiple values in a table, use renderViewHtml
, renderColumnHtml
, or renderTextOnlyValue
, in which case a Collection of all selected items will be passed to the closure. renderItemViewHtml
does not need to be implemented if using this approach.
For example, rendering multiple Versions in a table:
Definitions
The following script contains all closures with all possible parameters that you can use and other variables you can set.
Note that when an Issue
is provided, this is a "live" issue - it reflects changes made in the form during editing. This allows you to change possible selection values based on issue attributes, or indeed the current user roles and groups etc.