Uploaded image for project: 'Jira Data Center'
  1. Jira Data Center
  2. JRASERVER-79065

Version picker shows duplicate options, including the "(New Version)" option, when the REST API returns a single exact match

XMLWordPrintable

      Issue Summary

      The version picker component in JIRA issue creation/edit forms displays duplicate version options when users type a complete version name that exactly matches a single version returned by the REST API. Instead of showing only the matching version, the picker displays both the actual version (e.g., "Version 1") and a "New Version" option (e.g., "Version 1 (New Version)"), creating confusion for users who expect to see only the exact match.

      This issue occurs inconsistently across different projects, with some customers able to reproduce it reliably while others cannot in their environments. The affected Project needs to have hundreds of versions in order to reproduce the issue.

      Steps to Reproduce

      • Navigate to an JIRA project with large number of versions (hundreds) as Jira Project Administrator.
      • Click "Create Issue" or edit an existing issue.
      • In the version picker field (Fix Version/s or Affects Version/s), start typing a version name.
      • Type the complete, exact name of an existing version (e.g., "Version 1").
      • Wait for the REST API call to complete and return results.
      • Observe the dropdown options displayed.

      Expected Results

      When the REST API returns exactly one version that matches the typed text completely:

      • Only one option should be displayed in the dropdown: the exact matching version.
      • No "New Version" option should be shown since an exact match already exists.
      • Users should be able to select the single matching version without confusion.

      Actual Results

      When the REST API returns exactly one version that matches the typed text completely:

      • Two options are displayed in the dropdown:
        • The actual matching version (e.g., "Version 1")
        • A "New Version" option (e.g., "Version 1 (New Version)")
      • This creates confusion as users see what appears to be duplicate options
      • The issue occurs inconsistently - some projects are affected while others work correctly
      • The validation logic in OnlyNewItemsSuggestHandler.validateMirroring() incorrectly returns true for showing the "New Version" option even when an exact match exists

      Issue Root Cause

      The root cause is a race condition between the "(New Version)" option creation logic and the REST API response processing in the version picker component.
      Detailed Technical Root Cause:

      • User types a version name (e.g., "Version 1")
      • OnlyNewItemsSuggestHandler.validateMirroring() is called to determine if "(New Version)" should be shown
      • At this moment, the model's getDisplayableUnSelectedDescriptors() contains stale data (XYZ number of versions from initial load)
      • Simultaneously, an AJAX REST API call is made to fetch filtered versions
      • validateMirroring() finds no exact match in the stale model data and returns true - allowing "(New Version)" to be created
      • The REST API responds with exactly one matching version
      • formatSuggestions() is called with both the REST response (containing the exact match) AND the "(New Version)" option
      • Result: User sees both options in the dropdown

      The issue occurs because the validateMirroring() method checks the model state before the AJAX response has been integrated into the model, while formatSuggestions() receives the fresh AJAX data after the "(New Version)" option has already been created.

      This issue will affect only projects with a high enough number of versions for the rece condition to be met or Jira instances that are already suffering from poor performance.

      Workaround

      The workaround is optional due to the minor impact of the issue. The existing validation won't allow the user to create a duplicate version if they try. The workaround can be used until a permanent fix can be implemented in the core JIRA codebase through the OnlyNewItemsSuggestHandler.validateMirroring() method to properly handle the timing synchronization between REST API responses and model state updates.

      The workaround script should be added to the JIRA announcement banner using <script> tags. The script will automatically apply the fix when users access any page containing version picker fields, including:

      • Issue create pages
      • Issue edit pages
      • Quick create dialogs
      • Any other forms with version picker components

      The fix is designed to be safe and non-intrusive - it will gracefully handle any errors and fall back to the original behavior if needed. Users can verify the fix is working through browser console logs that will show when duplicate options are detected and removed.

      <script>
      // Simple banner fix for duplicate "(New Version)" issue
      (function() {
          'use strict';
          
          // Prevent multiple applications
          if (window.VERSION_PICKER_BANNER_FIX_APPLIED) {
              return;
          }
          
          var fixApplied = false;
          
          function applyVersionPickerFix() {
              if (fixApplied || !window.AJS || !AJS.OnlyNewItemsSuggestHandler || !window._) {
                  return;
              }
              
              console.log('Applying version picker fix...');
              
              var originalFormatSuggestions = AJS.OnlyNewItemsSuggestHandler.prototype.formatSuggestions;
              
              AJS.OnlyNewItemsSuggestHandler.prototype.formatSuggestions = function(descriptors, query) {
                  var result = originalFormatSuggestions.call(this, descriptors, query);
                  
                  // Only process if we have a query and results
                  if (!query || query.length === 0 || !result || result.length === 0) {
                      return result;
                  }
                  
                  var lowerCaseQuery = query.toLowerCase();
                  var hasExactMatch = false;
                  var hasNewVersionOption = false;
                  var newVersionItem = null;
                  
                  // Check what we have in the suggestions
                  _.each(result, function(groupDescriptor) {
                      if (groupDescriptor && groupDescriptor.items && typeof groupDescriptor.items === 'function') {
                          _.each(groupDescriptor.items(), function(item) {
                              if (item && typeof item.label === 'function') {
                                  var label = item.label();
                                  
                                  // Found exact match
                                  if (label && label.toLowerCase() === lowerCaseQuery && !item.properties.noExactMatch) {
                                      hasExactMatch = true;
                                  }
                                  
                                  // Found (New Version) option
                                  if (item.properties && item.properties.noExactMatch && label && label.toLowerCase() === lowerCaseQuery) {
                                      hasNewVersionOption = true;
                                      newVersionItem = item;
                                  }
                              }
                          });
                      }
                  });
                  
                  // Remove duplicate if both exist
                  if (hasExactMatch && hasNewVersionOption) {
                      console.log('Removing duplicate (New Version) option for:', query);
                      
                      _.each(result, function(groupDescriptor) {
                          if (groupDescriptor && groupDescriptor.items && typeof groupDescriptor.items === 'function') {
                              var originalItems = groupDescriptor.items();
                              var filteredItems = _.filter(originalItems, function(item) {
                                  return !(item.properties && item.properties.noExactMatch && item === newVersionItem);
                              });
                              
                              if (filteredItems.length < originalItems.length) {
                                  groupDescriptor.items(filteredItems);
                              }
                          }
                      });
                  }
                  
                  return result;
              };
              
              fixApplied = true;
              console.log('Fix applied successfully!');
          }
          
          // Hook into JIRA's existing event system
          function waitForJiraAndApply() {
              if (window.AJS && AJS.$ && typeof AJS.$(document).ready === 'function') {
                  AJS.$(document).ready(function() {
                      applyVersionPickerFix();
                  });
              } else if (window.jQuery) {
                  jQuery(document).ready(function() {
                      applyVersionPickerFix();
                  });
              } else {
                  // Fallback: try again in 100ms
                  setTimeout(waitForJiraAndApply, 100);
              }
          }
          
          window.VERSION_PICKER_BANNER_FIX_APPLIED = true;
          waitForJiraAndApply();
          
      })();
      </script>
      

        1. JRASERVER-79065-1.png
          1.05 MB
          Marko Radivojevic

              Unassigned Unassigned
              3984d3d058e8 Marko Radivojevic (Inactive)
              Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated: