2929
3030import edu .umd .cs .findbugs .annotations .CheckForNull ;
3131import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
32+ import hudson .ExtensionComponent ;
33+ import hudson .ExtensionList ;
3234import hudson .Util ;
3335import hudson .util .EditDistance ;
3436import io .jenkins .servlet .ServletExceptionWrapper ;
3739import java .util .AbstractList ;
3840import java .util .ArrayList ;
3941import java .util .Collections ;
42+ import java .util .Comparator ;
4043import java .util .HashSet ;
4144import java .util .List ;
45+ import java .util .Map ;
4246import java .util .Set ;
4347import java .util .logging .Level ;
4448import java .util .logging .Logger ;
49+ import java .util .stream .Collectors ;
4550import jenkins .model .Jenkins ;
51+ import jenkins .search .SearchGroup ;
4652import jenkins .security .stapler .StaplerNotDispatchable ;
4753import jenkins .util .MemoryReductionUtil ;
4854import jenkins .util .SystemProperties ;
@@ -171,11 +177,26 @@ public void doSuggest(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter
171177
172178 if (iconName .startsWith ("symbol" )) {
173179 r .suggestions .add (new Item (curItem .getPath (), curItem .getUrl (),
174- Symbol .get (new SymbolRequest .Builder ().withRaw (iconName ).build ())));
180+ Symbol .get (new SymbolRequest .Builder ().withRaw (iconName ).build ()), "symbol" , curItem . item . getSearchGroup (). getDisplayName () ));
175181 } else {
176- r .suggestions .add (new Item (curItem .getPath (), curItem .getUrl (), iconName , "image" ));
182+ r .suggestions .add (new Item (curItem .getPath (), curItem .getUrl (), iconName , "image" , curItem . item . getSearchGroup (). getDisplayName () ));
177183 }
178184 }
185+
186+ // Sort results by group
187+ ExtensionList <SearchGroup > groupsExtensionList = ExtensionList .lookup (SearchGroup .class );
188+ List <ExtensionComponent <SearchGroup >> components = groupsExtensionList .getComponents ();
189+ Map <String , Double > searchGroupOrdinal = components .stream ()
190+ .collect (Collectors .toMap (
191+ (k ) -> k .getInstance ().getDisplayName (),
192+ ExtensionComponent ::ordinal
193+ ));
194+ r .suggestions .sort (
195+ Comparator .comparingDouble ((Item item ) -> searchGroupOrdinal .getOrDefault (item .getGroup (), Double .MAX_VALUE ))
196+ .reversed ()
197+ .thenComparing (item -> item .name )
198+ );
199+
179200 rsp .serveExposedBean (req , r , new ExportConfig ());
180201 }
181202
@@ -270,7 +291,6 @@ public static class Result {
270291 public static class Item {
271292
272293 @ Exported
273- @ SuppressFBWarnings (value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD" , justification = "read by Stapler" )
274294 public String name ;
275295
276296 private final String url ;
@@ -279,22 +299,19 @@ public static class Item {
279299
280300 private final String icon ;
281301
302+ private final String group ;
303+
282304 public Item (String name ) {
283- this (name , null , null );
305+ this (name , null , null , "symbol" , null );
284306 }
285307
286- public Item (String name , String url , String icon ) {
308+ public Item (String name , String url , String icon , String type , String group ) {
287309 this .name = name ;
288310 this .url = url ;
289311 this .icon = icon ;
290- this .type = "symbol" ;
291- }
292-
293- public Item (String name , String url , String icon , String type ) {
294312 this .name = name ;
295- this .url = url ;
296- this .icon = icon ;
297313 this .type = type ;
314+ this .group = group ;
298315 }
299316
300317 @ Exported
@@ -311,6 +328,11 @@ public String getIcon() {
311328 public String getType () {
312329 return type ;
313330 }
331+
332+ @ Exported
333+ public String getGroup () {
334+ return group ;
335+ }
314336 }
315337
316338 private enum Mode {
0 commit comments