I have two custom fields (select lists) that need to have the same list of options at any given time. We'll consider one to be the "master" field where all changes are made, and the other to be "slave" field that will get updated anytime the master is changed. I tried to build this as a Scripted Listener, but it turns out that there isn't a reliable "Custom Field Updated" event for this, so I'm doing it as a Behavior instead. Basically, anytime the slave field shows up on a screen, it will run the Behavior script to make sure it is in sync with the master field.
I have all of my code working except for one weird bug.... Upon loading the screen with the slave field on it, I can see that the custom field options are updated correctly (by looking at the custom field configuration in the admin area), but when I look at the select list options on the screen, they're still a little off (the new option will be there, but not in the right spot, or the disabled options from the master field will still be showing up in the slave field options). If I close out of the screen and load it again, then everything looks great (I assume this is because it is pulling the options straight from the custom field context this time instead of using the setFieldOptions method). What I want to know is, why does the setFieldOptions method appear to not be working correctly? I can even debug the "ops" Map right before I call the setFieldOptions method and see that it has everything I need and in the correct order, but yet when I look in the UI it's all out of wack that first time. @Jamie Echlin [Adaptavist], do you have any ideas?
Here's the code I'm using, for reference (I know there are probably a billion ways to code this in a better way, but let's focus on my bug and not on syntax efficiencies for the moment ):
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.customfields.option.Option def optionsManager = ComponentAccessor.getOptionsManager() def customFieldManager = ComponentAccessor.getCustomFieldManager() def cf_maintenanceRelease = customFieldManager.getCustomFieldObject(17065L) def cf_mrLocked = customFieldManager.getCustomFieldObject(17066L) def mrFieldConfig = cf_maintenanceRelease.getRelevantConfig(getIssueContext()) def mrLockedFieldConfig = cf_mrLocked.getRelevantConfig(getIssueContext()) def originalOps = optionsManager.getOptions(mrFieldConfig) def currentMrLockedOps = optionsManager.getOptions(mrLockedFieldConfig) def originalOpsValuesArray = [] def originalOpsDisabledArray = [] def currentMrLockedOpsValuesArray = [] def currentMrLockedOpsDisabledArray = [] def originalOpsSize = originalOps.size() def ops = ["-1":"None"] def mrLockedFormField = getFieldByName("MR Locked") //Get an array of strings for each list of options originalOps.each{ originalOpsValuesArray << it.getValue() originalOpsDisabledArray << it.getDisabled() } currentMrLockedOps.each{ currentMrLockedOpsValuesArray << it.getValue() currentMrLockedOpsDisabledArray << it.getDisabled() } //If the two lists don't match, then sync 'em up if(originalOpsValuesArray != currentMrLockedOpsValuesArray || originalOpsDisabledArray != currentMrLockedOpsDisabledArray){ if(originalOpsValuesArray != currentMrLockedOpsValuesArray){ //Add values that are missing for(def i=0; i<originalOpsSize; i++){ if(!currentMrLockedOpsValuesArray.contains(originalOpsValuesArray[i])){ currentMrLockedOpsValuesArray.add(i, originalOpsValuesArray[i]) currentMrLockedOps.addOption(null, originalOps[i].getValue()) } } //Remove extraneous values def tmpSize = currentMrLockedOpsValuesArray.size() for(def i=0; i<tmpSize; i++){ if(!originalOpsValuesArray.contains(currentMrLockedOpsValuesArray[i])){ currentMrLockedOpsValuesArray.remove(i) tmpSize-- currentMrLockedOps.removeOption(currentMrLockedOps[i]) } } //Get the fresh set of options def updatedMrLockedOps = optionsManager.getOptions(cf_mrLocked.getRelevantConfig(getIssueContext())) //Create a map for the order sequence Map positionMap = [:] for(def i=0; i<originalOpsSize; i++){ positionMap.put(i, updatedMrLockedOps.find{ it.getValue() == originalOps[i].getValue() }) } //Update the order sequence updatedMrLockedOps.moveOptionToPosition(positionMap) } if(originalOpsDisabledArray != currentMrLockedOpsDisabledArray){ //Synchronize enabled/disabled for(def i=0; i<originalOpsSize; i++){ if(originalOps[i].getDisabled()){ optionsManager.disableOption(currentMrLockedOps.find{ it.getValue() == originalOps[i].getValue() }) } else { optionsManager.enableOption(currentMrLockedOps.find{ it.getValue() == originalOps[i].getValue() }) } } } //Update the Form Field def sortedOps = optionsManager.getOptions(cf_mrLocked.getRelevantConfig(getIssueContext())) sortedOps.each{ ops.put(it.getOptionId() as String, it.getValue()) } mrLockedFormField.setFieldOptions(ops) }
Community moderators have prevented the ability to post new answers.
It sounds like what your are describing is that the options you are setting are out of order. This was a bug and fixed from 4.3.2+ for JIRA 7 and 4.1.3.13+ for JIRA 6. Please see this issue for more details.
You should update to the latest version of ScriptRunner on marketplace for your version of JIRA which you can find here.
Thanks Adam, I'll work on getting the latest plugin version installed.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I just upgraded to the latest version (4.3.4) but it's still not working as expected. In fact, some of the functionality has regressed further. Now, when I add an option to the master field and look at the slave field options on the create screen, the new option doesn't show up at all (before, it would show up but it wouldn't be in the right place). Like before, if I close out of the create screen and bring it up again, then the slave options look fine. But for some reason the setFieldOptions() method does not appear to be working appropriately.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Nevermind, I found a different issue in my script that was not preventing the code to reach the bottom. Once I fixed that, I also changed the ops Map to be of type LinkedHashMap (to keep everything in the order it was submitted, instead of ordering on the key) and it appears to be working! Thanks for your help on this.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
No problem. Glad you got it sorted.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.