azkaban-aplcache

Refactor and bug fix on Job History page pagination (#2122) Fixes

2/27/2019 3:07:23 AM

Details

diff --git a/azkaban-web-server/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java b/azkaban-web-server/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
index 6a6d101..6008397 100644
--- a/azkaban-web-server/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
+++ b/azkaban-web-server/src/main/java/azkaban/webapp/servlet/ProjectManagerServlet.java
@@ -74,6 +74,7 @@ import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
@@ -1151,6 +1152,22 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
     final Page page =
         newPage(req, resp, session,
             "azkaban/webapp/servlet/velocity/jobhistorypage.vm");
+
+    final String jobId = getParam(req, "job");
+    page.add("jobId", jobId);
+
+    int pageNum = Math.max(1, getIntParam(req, "page", 1));
+    page.add("page", pageNum);
+
+    final int pageSize = Math.max(1, getIntParam(req, "size", 25));
+    page.add("pageSize", pageSize);
+
+    page.add("recordCount", 0);
+    page.add("projectId", "");
+    page.add("projectName", "");
+    page.add("dataSeries", "[]");
+    page.add("history", null);
+
     final String projectName = getParam(req, "project");
     final User user = session.getUser();
 
@@ -1166,88 +1183,36 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
       return;
     }
 
-    final String jobId = getParam(req, "job");
-    final int pageNum = getIntParam(req, "page", 1);
-    final int pageSize = getIntParam(req, "size", 25);
-
     page.add("projectId", project.getId());
     page.add("projectName", project.getName());
-    page.add("jobid", jobId);
-    page.add("page", pageNum);
-
-    final int skipPage = (pageNum - 1) * pageSize;
 
-    int numResults = 0;
     try {
-      numResults = this.executorManagerAdapter.getNumberOfJobExecutions(project, jobId);
-      final int maxPage = (numResults / pageSize) + 1;
-      List<ExecutableJobInfo> jobInfo =
-          this.executorManagerAdapter.getExecutableJobs(project, jobId, skipPage, pageSize);
+      final int numResults = this.executorManagerAdapter.getNumberOfJobExecutions(project, jobId);
+      page.add("recordCount", numResults);
 
-      if (jobInfo == null || jobInfo.isEmpty()) {
-        jobInfo = null;
+      final int totalPages = ((numResults - 1) / pageSize) + 1;
+      if (pageNum > totalPages) {
+        pageNum = totalPages;
+        page.add("page", pageNum);
       }
-      page.add("history", jobInfo);
+      final int elementsToSkip = (pageNum - 1) * pageSize;
+      final List<ExecutableJobInfo> jobInfo =
+          this.executorManagerAdapter.getExecutableJobs(project, jobId, elementsToSkip, pageSize);
 
-      page.add("previous", new PageSelection("Previous", pageSize, true, false,
-          Math.max(pageNum - 1, 1)));
+      if (CollectionUtils.isNotEmpty(jobInfo)) {
+        page.add("history", jobInfo);
 
-      page.add(
-          "next",
-          new PageSelection("Next", pageSize, false, false, Math.min(
-              pageNum + 1, maxPage)));
-
-      if (jobInfo != null) {
         final ArrayList<Object> dataSeries = new ArrayList<>();
         for (final ExecutableJobInfo info : jobInfo) {
           final Map<String, Object> map = info.toObject();
           dataSeries.add(map);
         }
         page.add("dataSeries", JSONUtils.toJSON(dataSeries));
-      } else {
-        page.add("dataSeries", "[]");
       }
     } catch (final ExecutorManagerException e) {
       page.add("errorMsg", e.getMessage());
     }
 
-    // Now for the 5 other values.
-    int pageStartValue = 1;
-    if (pageNum > 3) {
-      pageStartValue = pageNum - 2;
-    }
-    final int maxPage = (numResults / pageSize) + 1;
-
-    page.add(
-        "page1",
-        new PageSelection(String.valueOf(pageStartValue), pageSize,
-            pageStartValue > maxPage, pageStartValue == pageNum, Math.min(
-            pageStartValue, maxPage)));
-    pageStartValue++;
-    page.add(
-        "page2",
-        new PageSelection(String.valueOf(pageStartValue), pageSize,
-            pageStartValue > maxPage, pageStartValue == pageNum, Math.min(
-            pageStartValue, maxPage)));
-    pageStartValue++;
-    page.add(
-        "page3",
-        new PageSelection(String.valueOf(pageStartValue), pageSize,
-            pageStartValue > maxPage, pageStartValue == pageNum, Math.min(
-            pageStartValue, maxPage)));
-    pageStartValue++;
-    page.add(
-        "page4",
-        new PageSelection(String.valueOf(pageStartValue), pageSize,
-            pageStartValue > maxPage, pageStartValue == pageNum, Math.min(
-            pageStartValue, maxPage)));
-    pageStartValue++;
-    page.add(
-        "page5",
-        new PageSelection(String.valueOf(pageStartValue), pageSize,
-            pageStartValue > maxPage, pageStartValue == pageNum, Math.min(
-            pageStartValue, maxPage)));
-
     page.render();
   }
 
@@ -1657,7 +1622,8 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
         status = "error";
       }
     }
-    final String response = createJsonResponse(status, message, action, params);
+    final String response = AbstractAzkabanServlet
+        .createJsonResponse(status, message, action, params);
     try {
       final Writer write = resp.getWriter();
       write.append(response);
@@ -1679,7 +1645,7 @@ public class ProjectManagerServlet extends LoginAbstractAzkabanServlet {
     final User user = session.getUser();
     final String projectName = (String) multipart.get("project");
     final Project project = this.projectManager.getProject(projectName);
-    if(project == null || !project.isActive()) {
+    if (project == null || !project.isActive()) {
       final String failureCause = project == null ? "doesn't exist." : "was already removed.";
       registerError(ret, "Installation Failed. Project '" + projectName + " "
           + failureCause, resp, 410);
diff --git a/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm b/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
index e3d1d62..f25fd9f 100644
--- a/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
+++ b/azkaban-web-server/src/main/resources/azkaban/webapp/servlet/velocity/jobhistorypage.vm
@@ -23,6 +23,7 @@
 
   <script type="text/javascript" src="${context}/js/raphael.min.js"></script>
   <script type="text/javascript" src="${context}/js/morris.min.js"></script>
+  <script type="text/javascript" src="${context}/js/jquery.twbsPagination.min.js"></script>
   <script type="text/javascript" src="${context}/js/azkaban/util/date.js"></script>
   <script type="text/javascript" src="${context}/js/azkaban/view/time-graph.js"></script>
   <script type="text/javascript" src="${context}/js/azkaban/view/job-history.js"></script>
@@ -35,8 +36,23 @@
 
     var projectId = "$projectId";
     var projectName = "$projectName";
-    var jobName = "$jobid";
+    var jobName = "$jobId";
     var dataSeries = $dataSeries;
+
+    var jobHistoryPageSettings = {
+      projectName: "${projectName}",
+      jobId: "${jobId}",
+      dataSeries: ${dataSeries},
+      page: ${page},
+      pageSize: ${pageSize},
+      visiblePages: 5,
+      recordCount: ${recordCount},
+      fetchJobHistoryUrl: contextURL + "/manager"
+    };
+
+    $(function () {
+      initJobHistoryPage(jobHistoryPageSettings);
+    });
   </script>
   <link rel="stylesheet" type="text/css" href="${context}/css/morris.css"/>
 </head>
@@ -53,8 +69,8 @@
 
   <div class="az-page-header page-header-bare">
     <div class="container-full">
-      <h1><a href="${context}/manager?project=${projectName}&job=${jobid}&history">Job History
-        <small>$jobid</small>
+      <h1><a href="${context}/manager?project=${projectName}&job=${jobId}&history">Job History
+        <small>$jobId</small>
       </a></h1>
     </div>
   </div>
@@ -64,7 +80,7 @@
         <li><a
             href="${context}/manager?project=${projectName}"><strong>Project</strong> $projectName
         </a></li>
-        <li class="active"><strong>Job History</strong> $jobid</li>
+        <li class="active"><strong>Job History</strong> $jobId</li>
       </ol>
     </div>
   </div>
@@ -106,7 +122,9 @@
                   #end
                 </td>
                 <td>
-                  <a href="${context}/manager?project=${projectName}&flow=${job.immediateFlowId}&job=${jobid}">${jobid}</a>
+                  <a href="${context}/manager?project=${projectName}&flow=${job.immediateFlowId}&job=${jobId}">
+                    ${jobId}
+                  </a>
                 </td>
                 <td>
                   <a href="${context}/manager?project=${projectName}&flow=${job.immediateFlowId}">${job.immediateFlowId}</a>
@@ -132,35 +150,7 @@
           </tbody>
         </table>
 
-        <ul class="pagination" id="pageSelection">
-          <li id="previous" class="first"><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${previous.nextPage}&size=${previous.size}"><span
-              class="arrow">&larr;</span>Previous</a></li>
-          <li id="page1" #if($page1.selected) class="active" #elseif ($page1.disabled)
-              class="disabled" #end><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${page1.nextPage}&size=${page1.size}">${page1.page}</a>
-          </li>
-          <li id="page2" #if($page2.selected) class="active" #elseif ($page2.disabled)
-              class="disabled" #end><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${page2.nextPage}&size=${page2.size}">${page2.page}</a>
-          </li>
-          <li id="page3" #if($page3.selected) class="active" #elseif ($page3.disabled)
-              class="disabled" #end><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${page3.nextPage}&size=${page3.size}">${page3.page}</a>
-          </li>
-          <li id="page4" #if($page4.selected) class="active" #elseif ($page4.disabled)
-              class="disabled" #end><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${page4.nextPage}&size=${page4.size}">${page4.page}</a>
-          </li>
-          <li id="page5" #if($page5.selected) class="active" #elseif ($page5.disabled)
-              class="disabled" #end><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${page5.nextPage}&size=${page5.size}">${page5.page}</a>
-          </li>
-          <li id="next"><a
-              href="${context}/manager?project=${projectName}&job=${jobid}&history&page=${next.nextPage}&size=${next.size}">Next<span
-              class="arrow">&rarr;</span></a></li>
-        </ul>
-
+        <ul id="jobHistoryPagination" class="pagination"></ul>
       </div><!-- /.col-xs-12 -->
     </div><!-- /.row -->
 
diff --git a/azkaban-web-server/src/web/js/azkaban/view/job-history.js b/azkaban-web-server/src/web/js/azkaban/view/job-history.js
index c52a0ff..ea61ae9 100644
--- a/azkaban-web-server/src/web/js/azkaban/view/job-history.js
+++ b/azkaban-web-server/src/web/js/azkaban/view/job-history.js
@@ -21,18 +21,44 @@ var jobHistoryView;
 var dataModel;
 azkaban.DataModel = Backbone.Model.extend({});
 
-$(function () {
-  var selected;
-  var series = dataSeries;
-  dataModel = new azkaban.DataModel();
-  dataModel.set({
-    "data": series
+var initJobHistoryPage = function (settings) {
+  dataModel = new azkaban.DataModel({
+    page: settings.page,
+    pageSize: settings.pageSize,
+    visiblePages: settings.visiblePages,
+    recordCount: settings.recordCount,
+    dataSeries: settings.dataSeries,
+    projectName: settings.projectName,
+    jobId: settings.jobId,
+    fetchJobHistoryUrl: settings.fetchJobHistoryUrl
   });
+
   dataModel.trigger('render');
 
   jobHistoryView = new azkaban.TimeGraphView({
     el: $('#timeGraph'),
     model: dataModel,
-    modelField: "data"
+    modelField: "dataSeries"
   });
-});
+
+  if (settings.recordCount) {
+    $('#jobHistoryPagination').twbsPagination({
+      totalPages: Math.ceil(
+          dataModel.get("recordCount") / dataModel.get("pageSize")),
+      startPage: dataModel.get("page"),
+      initiateStartPageClick: false,
+      visiblePages: dataModel.get("visiblePages"),
+      onPageClick: function (event, page) {
+        var qparams = {
+          "project": dataModel.get("projectName"),
+          "job": dataModel.get("jobId"),
+          "page": page,
+          "size": dataModel.get("pageSize")
+        };
+        window.location.href = dataModel.get("fetchJobHistoryUrl") + "?history&"
+            + $.param(qparams);
+      }
+    });
+  }
+
+};