Add config option for panels jobs ordering

Right now jobs ordering for JobsPanel and JobsDropDownPanel is
hardcoded as 'REPORTER' which is inconvenient in case when you
have some CI pipelines in place and so expect statuses to be
sorted by report time to be in accordance with pipeline flow.
This change introduces two more config options to control jobs
ordering in plugin panels. Possible sort options are REPORTER, NAME
and DATE. Default is REPORTER so the change is fully backward
compatible. Config example:
  [plugin "verify-status"]
     sortJobsDropDownPanel = NAME
     sortJobsPanel = DATE

Change-Id: I27605c35b731bb088346aabe056c67eef4905f54
Signed-off-by: Sergii Kipot <kipot.sergey@gmail.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/ConfigInfo.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/ConfigInfo.java
index 4538e86..00ac98a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/ConfigInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/ConfigInfo.java
@@ -20,10 +20,14 @@
   final native boolean showJobsSummaryPanel() /*-{ return this.show_jobs_summary_panel ? true : false; }-*/;
   final native boolean showJobsPanel() /*-{ return this.show_jobs_panel ? true : false; }-*/;
   final native boolean showJobsDropDownPanel() /*-{ return this.show_jobs_drop_down_panel ? true : false; }-*/;
+  final native String sortJobsPanel() /*-{ return this.sort_jobs_panel }-*/;
+  final native String sortJobsDropDownPanel() /*-{ return this.sort_jobs_drop_down_panel }-*/;
 
   final native void setShowJobsSummaryPanel(boolean s) /*-{ this.show_jobs_summary_panel = s; }-*/;
   final native void setShowJobsPanel(boolean s) /*-{ this.show_jobs_panel = s; }-*/;
   final native void setShowJobsDropDownPanel(boolean s) /*-{ this.show_jobs_drop_down_panel = s; }-*/;
+  final native void setSortJobsPanel(String s) /*-{ this.sort_jobs_panel = s; }-*/;
+  final native void setSortJobsDropDownPanel(String s) /*-{ this.sort_jobs_drop_down_panel = s; }-*/;
 
   static ConfigInfo create() {
     ConfigInfo g = (ConfigInfo) createObject();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsDropDownPanel.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsDropDownPanel.java
index e3a9e31..c4c5dc7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsDropDownPanel.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsDropDownPanel.java
@@ -36,6 +36,12 @@
  */
 public class JobsDropDownPanel extends FlowPanel {
   static class Factory implements Panel.EntryPoint {
+    private final ConfigInfo info;
+
+    public Factory(ConfigInfo info) {
+      this.info = info;
+    }
+
     @Override
     public void onLoad(Panel panel) {
       RevisionInfo rev =
@@ -44,11 +50,11 @@
         return;
       }
 
-      panel.setWidget(new JobsDropDownPanel(panel));
+      panel.setWidget(new JobsDropDownPanel(panel, info));
     }
   }
 
-  JobsDropDownPanel(Panel panel) {
+  JobsDropDownPanel(Panel panel, ConfigInfo info) {
     ChangeInfo change =
         panel.getObject(GerritUiExtensionPoint.Key.CHANGE_INFO).cast();
     String decodedChangeId = URL.decodePathSegment(change.id());
@@ -56,7 +62,7 @@
         panel.getObject(GerritUiExtensionPoint.Key.REVISION_INFO).cast();
     new RestApi("changes").id(decodedChangeId).view("revisions").id(rev.id())
         .view(Plugin.get().getPluginName(), "verifications")
-        .addParameter("sort", "REPORTER")
+        .addParameter("sort", info.sortJobsDropDownPanel())
         .addParameter("filter", "CURRENT")
         .get(new AsyncCallback<NativeMap<VerificationInfo>>() {
           @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsPanel.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsPanel.java
index 81465b1..1902487 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsPanel.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/JobsPanel.java
@@ -36,6 +36,12 @@
  */
 public class JobsPanel extends FlowPanel {
   static class Factory implements Panel.EntryPoint {
+    private final ConfigInfo info;
+
+    public Factory(ConfigInfo info) {
+      this.info = info;
+    }
+
     @Override
     public void onLoad(Panel panel) {
       RevisionInfo rev =
@@ -44,11 +50,11 @@
         return;
       }
 
-      panel.setWidget(new JobsPanel(panel));
+      panel.setWidget(new JobsPanel(panel, info));
     }
   }
 
-  JobsPanel(Panel panel) {
+  JobsPanel(Panel panel, ConfigInfo info) {
     final ChangeInfo change =
         panel.getObject(GerritUiExtensionPoint.Key.CHANGE_INFO).cast();
     String decodedChangeId = URL.decodePathSegment(change.id());
@@ -56,7 +62,8 @@
         panel.getObject(GerritUiExtensionPoint.Key.REVISION_INFO).cast();
     new RestApi("changes").id(decodedChangeId).view("revisions").id(rev.id())
         .view(Plugin.get().getPluginName(), "verifications")
-        .addParameter("sort", "REPORTER").addParameter("filter", "CURRENT")
+        .addParameter("sort", info.sortJobsPanel())
+        .addParameter("filter", "CURRENT")
         .get(new AsyncCallback<NativeMap<VerificationInfo>>() {
           @Override
           public void onSuccess(NativeMap<VerificationInfo> result) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/VerifyStatusPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/VerifyStatusPlugin.java
index 2e2575c..d45824e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/VerifyStatusPlugin.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/client/VerifyStatusPlugin.java
@@ -42,12 +42,12 @@
             if (info.showJobsPanel()) {
               Plugin.get().panel(
                   GerritUiExtensionPoint.CHANGE_SCREEN_BELOW_CHANGE_INFO_BLOCK,
-                  new JobsPanel.Factory());
+                  new JobsPanel.Factory(info));
             }
             if (info.showJobsDropDownPanel()) {
               Plugin.get().panel(
                   GerritUiExtensionPoint.CHANGE_SCREEN_HEADER_RIGHT_OF_POP_DOWNS,
-                  new JobsDropDownPanel.Factory());
+                  new JobsDropDownPanel.Factory(info));
             }
           }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetConfig.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetConfig.java
index 8733fb0..f1d299a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetConfig.java
@@ -37,6 +37,10 @@
     info.showJobsPanel = cfg.getBoolean("showJobsPanel", true);
     info.showJobsDropDownPanel = cfg.getBoolean("showJobsDropDownPanel", true);
     info.showJobsSummaryPanel = cfg.getBoolean("showJobsSummaryPanel", true);
+    info.sortJobsPanel = cfg.getEnum(JobsSorting.values(),
+        "sortJobsPanel", JobsSorting.REPORTER);
+    info.sortJobsDropDownPanel = cfg.getEnum(JobsSorting.values(),
+        "sortJobsDropDownPanel", JobsSorting.REPORTER);
     return info;
   }
 
@@ -44,5 +48,7 @@
     Boolean showJobsPanel;
     Boolean showJobsDropDownPanel;
     Boolean showJobsSummaryPanel;
+    JobsSorting sortJobsPanel;
+    JobsSorting sortJobsDropDownPanel;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetVerifications.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetVerifications.java
index 6745b66..7e67516 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetVerifications.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/GetVerifications.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gwtorm.server.OrmException;
@@ -42,14 +43,10 @@
     this.schemaFactory = schemaFactory;
   }
 
-  private String sort;
-  private String filter;
-
   @Option(name = "--sort", aliases = {"-s"}, metaVar = "SORT",
       usage = "Sort the list by an entry")
-  public void setSort(String sort) {
-    this.sort = sort.toUpperCase();
-  }
+  private JobsSorting sort;
+  private String filter;
 
   @Option(name = "--filter", aliases = {"-f"}, metaVar = "FILTER",
       usage = "filter the results")
@@ -72,40 +69,50 @@
     return info;
   }
 
-  private void sortJobs(List<PatchSetVerification> jobs, String order) {
-    if (order.equals("REPORTER")) {
-      // sort the jobs list by reporter(A-Z)/Name(A-Z)/Granted(Z-A)
-      Collections.sort(jobs, new Comparator<PatchSetVerification>() {
-        @Override
-        public int compare(PatchSetVerification a, PatchSetVerification b) {
-          return new CompareToBuilder()
-              .append(a.getReporter(),b.getReporter())
-              .append(a.getName(), b.getName())
-              .append(b.getGranted(),a.getGranted())
-              .toComparison();
-        }
-      });
-    } else if (order.equals("NAME")) {
-      // sort the jobs list by Name(A-Z)/Granted(Z-A)
-      Collections.sort(jobs, new Comparator<PatchSetVerification>() {
-        @Override
-        public int compare(PatchSetVerification a, PatchSetVerification b) {
-          return new CompareToBuilder()
-              .append(a.getName(),b.getName())
-              .append(b.getGranted(),a.getGranted())
-              .toComparison();
-        }
-      });
-    } else if (order.equals("DATE")) {
-      // sort the jobs list by Granted(Z-A)
-      Collections.sort(jobs, new Comparator<PatchSetVerification>() {
-        @Override
-        public int compare(PatchSetVerification a, PatchSetVerification b) {
-          return new CompareToBuilder()
-              .append(b.getGranted(),a.getGranted())
-              .toComparison();
-        }
-      });
+  private void sortJobs(List<PatchSetVerification> jobs,
+    @Nullable JobsSorting order) {
+    if (order == null) {
+      return;
+    }
+    switch (order) {
+      case REPORTER:
+        // sort the jobs list by reporter(A-Z)/Name(A-Z)/Granted(Z-A)
+        Collections.sort(jobs, new Comparator<PatchSetVerification>() {
+          @Override
+          public int compare(PatchSetVerification a, PatchSetVerification b) {
+            return new CompareToBuilder()
+                .append(a.getReporter(),b.getReporter())
+                .append(a.getName(), b.getName())
+                .append(b.getGranted(),a.getGranted())
+                .toComparison();
+          }
+        });
+        break;
+      case NAME:
+        // sort the jobs list by Name(A-Z)/Granted(Z-A)
+        Collections.sort(jobs, new Comparator<PatchSetVerification>() {
+          @Override
+          public int compare(PatchSetVerification a, PatchSetVerification b) {
+            return new CompareToBuilder()
+                .append(a.getName(),b.getName())
+                .append(b.getGranted(),a.getGranted())
+                .toComparison();
+          }
+        });
+        break;
+      case DATE:
+        // sort the jobs list by Granted(Z-A)
+        Collections.sort(jobs, new Comparator<PatchSetVerification>() {
+          @Override
+          public int compare(PatchSetVerification a, PatchSetVerification b) {
+            return new CompareToBuilder()
+                .append(b.getGranted(),a.getGranted())
+                .toComparison();
+          }
+        });
+        break;
+      default:
+        break;
     }
   }
 
@@ -124,7 +131,7 @@
       if (filter != null && !filter.isEmpty()) {
         if (filter.equals("CURRENT") ) {
           // logic to get current jobs assumes list is sorted by reporter
-          sortJobs(result, "REPORTER");
+          sortJobs(result, JobsSorting.REPORTER);
           isSorted = true;
           String prevReporter = "";
           String prevName = "";
@@ -157,14 +164,8 @@
       }
 
       // sort jobs
-      if (sort != null && !sort.isEmpty()) {
-        if (sort.equals("REPORTER") && !isSorted) {
-          sortJobs(jobs, "REPORTER");
-        } else if (sort.equals("NAME")) {
-          sortJobs(jobs, "NAME");
-        } else if (sort.equals("DATE")) {
-          sortJobs(jobs, "DATE");
-        }
+      if ((sort != JobsSorting.REPORTER) || !isSorted) {
+        sortJobs(jobs, sort);
       }
 
       for (PatchSetVerification v : jobs) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/JobsSorting.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/JobsSorting.java
new file mode 100644
index 0000000..cb4b7dc
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/JobsSorting.java
@@ -0,0 +1,21 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.verifystatus.server;
+
+public enum JobsSorting {
+  DATE,
+  REPORTER,
+  NAME
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/PutConfig.java b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/PutConfig.java
index 9fee1a1..93f6bbb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/PutConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/verifystatus/server/PutConfig.java
@@ -41,6 +41,8 @@
     public Boolean showJobsPanel;
     public Boolean showJobsDropDownPanel;
     public Boolean showJobsSummaryPanel;
+    public String sortJobsPanel;
+    public String sortJobsDropDownPanel;
   }
 
   private final PluginConfigFactory cfgFactory;
@@ -84,6 +86,18 @@
     } else {
       cfg.unset("plugin", pluginName, "showJobsSummaryPanel");
     }
+    if (input.sortJobsPanel != null) {
+      cfg.setEnum("plugin", pluginName, "sortJobsPanel",
+          JobsSorting.valueOf(input.sortJobsPanel));
+    } else {
+      cfg.unset("plugin", pluginName, "sortJobsPanel");
+    }
+    if (input.sortJobsDropDownPanel != null) {
+      cfg.setEnum("plugin", pluginName, "sortJobsDropDownPanel",
+          JobsSorting.valueOf(input.sortJobsDropDownPanel));
+    } else {
+      cfg.unset("plugin", pluginName, "sortJobsDropDownPanel");
+    }
 
     cfg.save();
     cfgFactory.getFromGerritConfig(pluginName, true);
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index f80a646..17fe3a7 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -96,6 +96,8 @@
 |showJobsPanel          | Whether jobs panel should be displayed (default to true)|
 |showJobsDropDownPanel  | Whether jobs drop down panel should be displayed (default to true)|
 |showJobsSummaryPanel   | Whether jobs summary panel should be displayed (default to true)|
+|sortJobsPanel          | The order of jobs sorting on jobs panel (REPORTER,NAME,DATE default to REPORTER). Both upper and lower cases are allowed.|
+|sortJobsDropDownPanel  | The order of jobs sorting on jobs drop down panel (REPORTER,NAME,DATE default to REPORTER). Both upper and lower cases are allowed.|
 
 
 #### Example
diff --git a/src/main/resources/Documentation/rest-api-config.md b/src/main/resources/Documentation/rest-api-config.md
index c4936a5..eef5387 100644
--- a/src/main/resources/Documentation/rest-api-config.md
+++ b/src/main/resources/Documentation/rest-api-config.md
@@ -72,6 +72,8 @@
 |show_jobs_panel          | Whether jobs panel should be displayed|
 |show_jobs_drop_down_panel| Whether jobs drop down panel should be displayed|
 |show_jobs_summary_panel  | Whether jobs summary panel should be displayed|
+|sort_jobs_panel          | The order of jobs sorting on jobs panel (REPORTER,NAME,DATE)|
+|sort_jobs_drop_down_panel| The order of jobs sorting on jobs drop down panel (REPORTER,NAME,DATE)|
 
 
 SEE ALSO