Jelajahi Sumber

HUE-9072 [jb] Fix Oozie coordinator pagination

Ying Chen 6 tahun lalu
induk
melakukan
b7a9bd5834

+ 5 - 1
apps/jobbrowser/src/jobbrowser/api2.py

@@ -72,7 +72,11 @@ def job(request, interface=None):
   interface = interface or json.loads(request.POST.get('interface'))
   app_id = json.loads(request.POST.get('app_id'))
 
-  response_app = get_api(request.user, interface, cluster=cluster).app(app_id)
+  if interface == 'schedules':
+    offset = json.loads(request.POST.get('pagination', '{"offset": 1}')).get('offset')
+    response_app = get_api(request.user, interface, cluster=cluster).app(app_id, offset=offset)
+  else :
+    response_app = get_api(request.user, interface, cluster=cluster).app(app_id)
 
   if response_app.get('status') == -1 and response_app.get('message'):
     response.update(response_app)

+ 17 - 3
apps/jobbrowser/src/jobbrowser/apis/schedule_api.py

@@ -68,11 +68,13 @@ class ScheduleApi(Api):
     }
 
 
-  def app(self, appid):
+  def app(self, appid, offset=1):
     oozie_api = get_oozie(self.user)
     coordinator = oozie_api.get_coordinator(jobid=appid)
 
-    request = MockDjangoRequest(self.user, get=MockGet())
+    mock_get = MockGet()
+    mock_get.update('offset', offset)
+    request = MockDjangoRequest(self.user, get=mock_get)
     response = list_oozie_coordinator(request, job_id=appid)
 
     common = {
@@ -164,14 +166,26 @@ class ScheduleApi(Api):
 
 
 class MockGet(object):
+  _prop = None
+
   def __ini__(self, statuses):
     self.statuses = []
 
+  @property
+  def properties(self):
+    if self._prop == None:
+      self._prop = {}
+    return self._prop
+
+  def update(self, prop, value):
+    if prop != 'format':
+      self.properties.update({prop: value})
+
   def get(self, prop, default=None):
     if prop == 'format':
       return 'json'
     else:
-      return default
+      return self._prop.get(prop, default)
 
   def getlist(self, prop):
     return []

+ 49 - 6
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -451,6 +451,9 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
               <!-- /ko -->
               <!-- /ko -->
 
+              <!-- ko if: $root.job() && $root.job().hasPagination() && interface() === 'schedules' -->
+              <div data-bind="template: { name: 'pagination${ SUFFIX }', data: $root.job() }, visible: !jobs.loadingJobs()"></div>
+              <!-- /ko -->
               <div data-bind="template: { name: 'pagination${ SUFFIX }', data: $root.jobs }, visible: !$root.job() && !jobs.loadingJobs()"></div>
               <!-- /ko -->
 
@@ -2012,14 +2015,14 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
             <tbody data-bind="foreach: properties['actions']">
               <tr>
                 <td>
-                  <a data-bind="hueLink: '/jobbrowser/jobs/' + externalId(), clickBubble: false">
+                  <a data-bind="hueLink: '/jobbrowser/jobs/' + ko.unwrap(externalId), clickBubble: false">
                     <i class="fa fa-tasks"></i>
                   </a>
                 </td>
                 <td data-bind="text: status"></td>
                 <td data-bind="text: errorMessage"></td>
                 <td data-bind="text: errorCode"></td>
-                <td data-bind="text: externalId, click: function() { $root.job().id(externalId()); $root.job().fetchJob();}, style: { color: '#0B7FAD' }" class="pointer"></td>
+                <td data-bind="text: externalId, click: function() { $root.job().id(ko.unwrap(externalId)); $root.job().fetchJob();}, style: { color: '#0B7FAD' }" class="pointer"></td>
                 <td data-bind="text: id, click: function() {  $root.job().id(id); $root.job().fetchJob(); }, style: { color: '#0B7FAD' }" class="pointer"></td>
                 <td data-bind="moment: {data: startTime, format: 'LLL'}"></td>
                 <td data-bind="moment: {data: endTime, format: 'LLL'}"></td>
@@ -2323,7 +2326,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
             </tr>
             </thead>
             <tbody data-bind="foreach: properties['actions']">
-              <tr class="status-border pointer" data-bind="css: {'completed': status() == 'SUCCEEDED', 'running': ['SUCCEEDED', 'FAILED', 'KILLED'].indexOf(status()) != -1, 'failed': status() == 'FAILED' || status() == 'KILLED'}, click: function() { if (id()) { $root.job().id(id()); $root.job().fetchJob();} }">
+              <tr class="status-border pointer" data-bind="css: {'completed': ko.unwrap(status) == 'SUCCEEDED', 'running': ['SUCCEEDED', 'FAILED', 'KILLED'].indexOf(ko.unwrap(status)) != -1, 'failed': ko.unwrap(status) == 'FAILED' || ko.unwrap(status) == 'KILLED'}, click: function() { if (ko.unwrap(id)) { $root.job().id(ko.unwrap(id)); $root.job().fetchJob();} }">
                 <td><span class="label job-status-label" data-bind="text: status"></span></td>
                 <td data-bind="text: name"></td>
                 <td data-bind="text: type"></td>
@@ -2533,6 +2536,42 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
     var Job = function (vm, job) {
       var self = this;
 
+      self.paginationPage = ko.observable(1);
+      self.paginationOffset = ko.observable(1); // Starting index
+      self.paginationResultPage = ko.observable(50);
+      self.totalApps = ko.observable(null);
+      self.hasPagination = ko.computed(function() {
+        return ['workflows', 'schedules', 'bundles'].indexOf(vm.interface()) != -1;
+      });
+      self.pagination = ko.pureComputed(function() {
+        return {
+          'page': self.paginationPage(),
+          'offset': self.paginationOffset(),
+          'limit': self.paginationResultPage()
+        };
+      });
+
+      self.pagination.subscribe(function(value) {
+        if (vm.interface() === 'schedules' && value.page > 1) {
+          vm.interface('schedules');
+          self.hasPagination(true);
+          self.fetchJob();
+        }
+      });
+
+      self.showPreviousPage = ko.computed(function() {
+        return self.paginationOffset() > 1;
+      });
+      self.showNextPage = ko.computed(function() {
+        return self.totalApps() != null && (self.paginationOffset() + self.paginationResultPage()) < self.totalApps();
+      });
+      self.previousPage = function() {
+        self.paginationOffset(self.paginationOffset() - self.paginationResultPage());
+      };
+      self.nextPage = function() {
+        self.paginationOffset(self.paginationOffset() + self.paginationResultPage());
+      };
+
       self.id = ko.observableDefault(job.id);
       %if not is_mini:
       self.id.subscribe(function () {
@@ -2614,7 +2653,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
         if (self.mainType() == 'schedules' && self.properties['tasks']) {
           var apps = self.properties['tasks']().map(function (instance) {
             var job = new CoordinatorAction(vm, ko.mapping.toJS(instance), self);
-            job.properties = instance;
+            job.properties = ko.mapping.fromJS(instance);
             return job;
           });
           var instances = new Jobs(vm);
@@ -2737,7 +2776,8 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
         return $.post("/jobbrowser/api/job/" + vm.interface(), {
           cluster: ko.mapping.toJSON(vm.compute),
           app_id: ko.mapping.toJSON(self.id),
-          interface: ko.mapping.toJSON(vm.interface)
+          interface: ko.mapping.toJSON(vm.interface),
+          pagination: ko.mapping.toJSON(self.pagination)
         }, function (data) {
           if (data.status == 0) {
             if (data.app) {
@@ -2745,7 +2785,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
             }
             if (callback) {
               callback(data);
-            };
+            }
           } else {
             $(document).trigger("error", data.message);
           }
@@ -2912,6 +2952,9 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
                   })
                 )
               }
+              if (vm.job().type() == 'schedule') {
+                self.totalApps(data.app.properties.total_actions);
+              }
             } else {
               requests.push(vm.job().fetchStatus());
             }

+ 1 - 1
apps/oozie/src/oozie/views/dashboard.py

@@ -454,7 +454,7 @@ def list_oozie_workflow(request, job_id):
 @show_oozie_error
 def list_oozie_coordinator(request, job_id):
   kwargs = {'cnt': 50, 'filters': []}
-  kwargs['offset'] = request.GET.get('offset', 1)
+  kwargs['offset'] = request.GET.get('offset', default=1)
   if request.GET.getlist('status'):
       kwargs['filters'].extend([('status', status) for status in request.GET.getlist('status')])