changeset 6132:190cb30841de

branches: fix performance of branch selectors with many branches - only show the first 200 results The way we use select2, it will cause browser performance problems when a select list contains thousands of entries. The primary bottleneck is the DOM creation, secondarily for the query to filter through the entries and decide what to show. We thus primarily have to limit how many entries we put in the drop-down, secondarily limit the iteration over data. One tricky case is where the user specifies a short but full branch name (like 'trunk') but many other branches contains the same string (not necessarily at the beginning, like 'for-trunk-next-week') which come before the perfect match in the branch list. It is thus not a solution to just stop searching when a fixed amount of matches have been found. Instead, we limit the amount of ordinary query matches, but always show all prefix matches. We thus always have to iterate through all entries, but we start using the (presumably) cheaper prefix search when the limit has been reached. There is no filtering initially when there is no query term, so that case has to be handled specially. Upstream select2 is now at 4.x. Upgrading is not trivial, and getting this fixed properly upstream is not a short term solution. Instead, we customize our copy. The benefit from this patch is bigger than the overhead of "maintaining" it locally.
author Mads Kiilerich <madski@unity3d.com>
date Thu, 28 Jul 2016 16:34:49 +0200
parents 6b723a49a9a1
children cc18e56220a2
files kallithea/public/js/select2/select2.js kallithea/templates/changelog/changelog.html kallithea/templates/files/files.html kallithea/templates/pullrequests/pullrequest.html
diffstat 4 files changed, 25 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/public/js/select2/select2.js	Fri Aug 12 03:13:59 2016 +0200
+++ b/kallithea/public/js/select2/select2.js	Thu Jul 28 16:34:49 2016 +0200
@@ -1097,7 +1097,13 @@
 
                         // collect the created nodes for bulk append
                         var nodes = [];
-                        for (i = 0, l = results.length; i < l; i = i + 1) {
+
+                        // Kallithea customization: maxResults
+                        l = results.length;
+                        if (query.term.length == 0 && l > opts.maxResults) {
+                            l = opts.maxResults;
+                        }
+                        for (i = 0; i < l; i = i + 1) {
 
                             result=results[i];
 
@@ -1138,6 +1144,10 @@
                             nodes.push(node[0]);
                         }
 
+                        if (results.length >= opts.maxResults) {
+                            nodes.push($('<li class="select2-no-results"><div class="select2-result-label">Too many matches found</div></li>'));
+                        }
+
                         // bulk append the created nodes
                         container.append(nodes);
                         liveRegion.text(opts.formatMatches(results.length));
@@ -1161,16 +1171,25 @@
 
             if (select) {
                 opts.query = this.bind(function (query) {
+                    // Kallithea customization: maxResults
                     var data = { results: [], more: false },
                         term = query.term,
-                        children, placeholderOption, process;
+                        children, placeholderOption, process,
+                        maxResults = opts.maxResults || -1,
+                        termLower = term.toLowerCase();
 
                     process=function(element, collection) {
                         var group;
                         if (element.is("option")) {
+                          if (collection.length < maxResults) {
                             if (query.matcher(term, element.text(), element)) {
                                 collection.push(self.optionToData(element));
                             }
+                          } else {
+                            if (element.text().toLowerCase().indexOf(termLower) == 0) {
+                                collection.push(self.optionToData(element));
+                            }
+                          }
                         } else if (element.is("optgroup")) {
                             group=self.optionToData(element);
                             element.children().each2(function(i, elm) { process(elm, group.children); });
--- a/kallithea/templates/changelog/changelog.html	Fri Aug 12 03:13:59 2016 +0200
+++ b/kallithea/templates/changelog/changelog.html	Thu Jul 28 16:34:49 2016 +0200
@@ -308,7 +308,7 @@
                 // change branch filter
                 $("#branch_filter").select2({
                     dropdownAutoWidth: true,
-                    minimumInputLength: 1,
+                    maxResults: 50,
                     sortResults: branchSort
                     });
 
--- a/kallithea/templates/files/files.html	Fri Aug 12 03:13:59 2016 +0200
+++ b/kallithea/templates/files/files.html	Thu Jul 28 16:34:49 2016 +0200
@@ -233,7 +233,7 @@
     // change branch filter
     $("#branch_selector").select2({
         dropdownAutoWidth: true,
-        minimumInputLength: 1,
+        maxResults: 50,
         sortResults: branchSort
         });
 
--- a/kallithea/templates/pullrequests/pullrequest.html	Fri Aug 12 03:13:59 2016 +0200
+++ b/kallithea/templates/pullrequests/pullrequest.html	Thu Jul 28 16:34:49 2016 +0200
@@ -202,6 +202,7 @@
 
       $("#org_ref").select2({
           dropdownAutoWidth: true,
+          maxResults: 50,
           sortResults: branchSort
       });
       $("#org_ref").on("change", function(e){
@@ -217,6 +218,7 @@
 
       $("#other_ref").select2({
           dropdownAutoWidth: true,
+          maxResults: 50,
           sortResults: branchSort
       });
       $("#other_ref").on("change", function(e){