瀏覽代碼

HUE-8589 [jb] Switch from compute to the cluster API endpoint in the job browser

Johan Ahlen 7 年之前
父節點
當前提交
84ee44f

+ 14 - 14
apps/jobbrowser/src/jobbrowser/templates/job_browser.mako

@@ -86,8 +86,8 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
       name: 'hue-context-selector',
       params: {
         sourceType: 'jobs',
-        compute: compute,
-        onComputeSelect: onComputeSelect,
+        cluster: cluster,
+        onClusterSelect: onClusterSelect,
         hideLabels: true
       }
     } --><!-- /ko -->
@@ -122,8 +122,8 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
               name: 'hue-context-selector',
               params: {
                 sourceType: 'jobs',
-                compute: compute,
-                onComputeSelect: onComputeSelect
+                cluster: cluster,
+                onClusterSelect: onClusterSelect
               }
             } --><!-- /ko -->
           </div>
@@ -236,7 +236,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
                     <i class="fa fa-refresh"></i>
                   </a>
 
-                  <a class="btn" title="${ _('Create cluster') }" data-bind="visible: $root.compute() && $root.compute()['type'].indexOf('altus') >= 0, click: jobs.createCluster">
+                  <a class="btn" title="${ _('Create cluster') }" data-bind="visible: $root.cluster() && $root.cluster()['type'].indexOf('altus') >= 0, click: jobs.createCluster">
                     <i class="fa fa-plus"></i>
                   </a>
                 <!-- /ko -->
@@ -2782,29 +2782,29 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
       self.clusterType = ko.observable();
       self.isMini = ko.observable(false);
 
-      self.compute = ko.observable();
+      self.cluster = ko.observable();
 
       self.availableInterfaces = ko.pureComputed(function () {
         var jobsInterfaceCondition = function () {
-          return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('yarn') != -1 && self.clusterType() != '${ ANALYTIC_DB }' && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
+          return self.appConfig() && self.appConfig()['browser'] && self.appConfig()['browser']['interpreter_names'].indexOf('yarn') != -1 && self.clusterType() != '${ ANALYTIC_DB }' && (!self.cluster() || self.cluster()['type'].indexOf('altus') == -1);
         };
         var dataEngInterfaceCondition = function () {
-          return self.compute() && self.compute()['type'].indexOf('altus-de') >= 0;
+          return self.cluster() && self.cluster()['type'].indexOf('altus-de') >= 0;
         };
         var dataWarehouseInterfaceCondition = function () {
-          return self.compute() && self.compute()['type'].indexOf('altus-dw') >= 0;
+          return self.cluster() && self.cluster()['type'].indexOf('altus-dw') >= 0;
         };
         var schedulerInterfaceCondition = function () {
-          return '${ user.has_hue_permission(action="access", app="oozie") }' == 'True' && self.clusterType() != '${ ANALYTIC_DB }' && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
+          return '${ user.has_hue_permission(action="access", app="oozie") }' == 'True' && self.clusterType() != '${ ANALYTIC_DB }' && (!self.cluster() || self.cluster()['type'].indexOf('altus') == -1);
         };
         var schedulerExtraInterfaceCondition = function () {
           return '${ is_mini }' == 'False' && schedulerInterfaceCondition();
         };
         var livyInterfaceCondition = function () {
-          return '${ is_mini }' == 'False' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('pyspark') != -1 && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
+          return '${ is_mini }' == 'False' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('pyspark') != -1 && (!self.cluster() || self.cluster()['type'].indexOf('altus') == -1);
         };
         var queryInterfaceCondition = function () {
-          return '${ ENABLE_QUERY_BROWSER.get() }' == 'True' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('impala') != -1 && (!self.compute() || self.compute()['type'].indexOf('altus') == -1);
+          return '${ ENABLE_QUERY_BROWSER.get() }' == 'True' && self.appConfig() && self.appConfig()['editor'] && self.appConfig()['editor']['interpreter_names'].indexOf('impala') != -1 && (!self.cluster() || self.cluster()['type'].indexOf('altus') == -1);
         };
 
         var interfaces = [
@@ -2908,7 +2908,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
         }
       };
 
-      self.onComputeSelect = function () {
+      self.onClusterSelect = function () {
         var interfaceToSet = self.interface();
         if (!self.availableInterfaces().some(function (availableInterface) {
           return availableInterface.interface === interfaceToSet;
@@ -2932,7 +2932,7 @@ ${ commonheader("Job Browser", "jobbrowser", user, request) | n,unicode }
         window.clearInterval(updateJobsInterval);
         if (self.interface() && self.interface() !== 'slas' && self.interface() !== 'oozie-info'){
           if (job) {
-            if (job.apiStatus() == 'RUNNING') {
+            if (job.apiStatus() === 'RUNNING') {
               updateJobInterval = setInterval(job.updateJob, 5000, 'jobbrowser');
             }
           }

+ 0 - 3
desktop/core/src/desktop/api2.py

@@ -166,9 +166,6 @@ def get_context_computes(request, interface):
       )
       # TODO if interface == 'spark2' keep only SPARK type
 
-  if interface == 'jobs':
-    return get_context_clusters(request, interface) # TODO remove when UI changed
-
   response[interface] = computes
   response['status'] = 0
 

+ 12 - 0
desktop/core/src/desktop/static/desktop/js/apiHelper.js

@@ -2046,6 +2046,18 @@ var ApiHelper = (function () {
     return self.simpleGet(url, undefined, options);
   };
 
+  /**
+   * @param {Object} options
+   * @param {boolean} [options.silenceErrors]
+   * @param {string} options.sourceType
+   * @return {Promise}
+   */
+  ApiHelper.prototype.fetchContextClusters = function (options) {
+    var self = this;
+    var url = '/desktop/api2/context/clusters/' + options.sourceType;
+    return self.simpleGet(url, undefined, options);
+  };
+
   ApiHelper.prototype.getClusterConfig = function (data) {
     return $.post(FETCH_CONFIG, data);
   };

+ 48 - 0
desktop/core/src/desktop/static/desktop/js/contextCatalog.js

@@ -44,6 +44,9 @@ var ContextCatalog = (function () {
 
       self.computes = {};
       self.computePromises = {};
+
+      self.clusters = {};
+      self.clusterPromises = {};
     }
 
     ContextCatalog.prototype.getStore = function () {
@@ -202,6 +205,39 @@ var ContextCatalog = (function () {
       return self.computePromises[options.sourceType];
     };
 
+    /**
+     * @param {Object} options
+     * @param {string} options.sourceType
+     * @param {boolean} [options.silenceErrors] - Default False
+     * @return {Promise}
+     */
+    ContextCatalog.prototype.getClusters = function (options) {
+      var self = this;
+
+      if (self.clusterPromises[options.sourceType]) {
+        return self.clusterPromises[options.sourceType];
+      }
+
+      if (self.clusters[options.sourceType]) {
+        self.clusterPromises[options.sourceType] = $.Deferred().resolve(self.clusters[options.sourceType]).promise();
+        return self.clusterPromises[options.sourceType];
+      }
+
+      var deferred = $.Deferred();
+      self.clusterPromises[options.sourceType] = deferred.promise();
+
+      ApiHelper.getInstance().fetchContextClusters(options).done(function (clusters) {
+        if (clusters && clusters[options.sourceType]) {
+          self.clusters[options.sourceType] = clusters[options.sourceType];
+          deferred.resolve(self.clusters[options.sourceType])
+        } else {
+          deferred.reject();
+        }
+      });
+
+      return self.clusterPromises[options.sourceType];
+    };
+
     return ContextCatalog;
   })();
 
@@ -209,6 +245,7 @@ var ContextCatalog = (function () {
     var contextCatalog = new ContextCatalog();
 
     return {
+
       /**
        * @param {Object} options
        * @param {string} options.sourceType
@@ -219,6 +256,7 @@ var ContextCatalog = (function () {
       getNamespaces: function (options) {
         return contextCatalog.getNamespaces(options);
       },
+
       /**
        * @param {Object} options
        * @param {string} options.sourceType
@@ -227,6 +265,16 @@ var ContextCatalog = (function () {
        */
       getComputes: function (options) {
         return contextCatalog.getComputes(options);
+      },
+
+      /**
+       * @param {Object} options
+       * @param {string} options.sourceType // TODO: rename?
+       * @param {boolean} [options.silenceErrors] - Default False
+       * @return {Promise}
+       */
+      getClusters: function (options) {
+        return contextCatalog.getClusters(options);
       }
     }
   })();

+ 66 - 2
desktop/core/src/desktop/templates/ko_components/ko_context_selector.mako

@@ -31,6 +31,15 @@ from desktop.views import _ko
 
     <div class="inline-block" style="display:none;" data-bind="visible: !loadingContext()">
       <!-- ko if: window.HAS_MULTI_CLUSTER -->
+      <!-- ko if: availableClusters().length > 0 && !hideClusters -->
+      <!-- ko ifnot: hideLabels --><span class="editor-header-title">${ _('Cluster') }</span><!-- /ko -->
+      <div data-bind="component: { name: 'hue-drop-down', params: { value: cluster, entries: availableClusters, labelAttribute: 'name', searchable: true, linkTitle: '${ _ko('Active cluster') }' } }" style="display: inline-block"></div>
+      <!-- /ko -->
+      <!-- ko if: availableClusters().length === 0 && !hideClusters -->
+      <span class="editor-header-title"><i class="fa fa-warning"></i> ${ _('No clusters found') }</span>
+      <!-- /ko -->
+
+
       <!-- ko if: availableComputes().length > 0 && !hideComputes -->
       <!-- ko ifnot: hideLabels --><span class="editor-header-title">${ _('Compute') }</span><!-- /ko -->
       <div data-bind="component: { name: 'hue-drop-down', params: { value: compute, entries: availableComputes, labelAttribute: 'name', searchable: true, linkTitle: '${ _ko('Active compute') }' } }" style="display: inline-block"></div>
@@ -82,10 +91,13 @@ from desktop.views import _ko
        *
        * @param {Object} params
        * @param {ko.observable|string} params.sourceType
+       * @param {ko.observable} [params.cluster]
        * @param {ko.observable} [params.compute]
        * @param {ko.observable} [params.namespace]
        * @param {ko.observable} [params.database]
        * @param {ko.observableArray} [params.availableDatabases]
+       * @param {boolean} [params.hideClusters] - Can be used to force hide cluster selection even if a cluster
+       *                                          observable is provided.
        * @param {boolean} [params.hideComputes] - Can be used to force hide compute selection even if a compute
        *                                          observable is provided.
        * @param {boolean} [params.hideNamespaces] - Can be used to force hide namespace selection even if a namespace
@@ -93,6 +105,7 @@ from desktop.views import _ko
        * @param {boolean} [params.hideDatabases] - Can be used to force hide database selection even if a database
        *                                           observable is provided.
        * @param {function} [params.onComputeSelect] - Callback when a new compute is selected (after initial set)
+       * @param {function} [params.onClusterSelect] - Callback when a new cluster is selected (after initial set)
        * @constructor
        */
       var HueContextSelector = function (params) {
@@ -102,12 +115,63 @@ from desktop.views import _ko
 
         self.sourceType = params.sourceType;
         self.disposals = [];
+        self.hideLabels = params.hideLabels;
+
+        self.loadingClusters = ko.observable(false);
+        self.availableClusters = ko.observableArray();
+        self.cluster = params.cluster;
+        self.hideClusters = params.hideClusters || !self.cluster;
+
+        if (self.cluster) {
+          self.loadingClusters(true);
+          self.lastClustersPromise = ContextCatalog.getClusters({ sourceType: ko.unwrap(self.sourceType) }).done(function (clusters) {
+            self.availableClusters(clusters);
+            if (!self.cluster() && apiHelper.getFromTotalStorage('contextSelector', 'lastSelectedCluster')) {
+              var lastSelectedCluster = apiHelper.getFromTotalStorage('contextSelector', 'lastSelectedCluster');
+              var found = clusters.some(function (cluster) {
+                if (cluster.id === lastSelectedCluster.id) {
+                  self.cluster(lastSelectedCluster);
+                  return true;
+                }
+              });
+
+              // If we can't find exact match we pick first based on type
+              if (!found) {
+                clusters.some(function (cluster) {
+                  if (cluster.type === lastSelectedCluster.type) {
+                    self.cluster(cluster);
+                    return true;
+                  }
+                });
+              }
+            }
+
+            if (!self.cluster()) {
+              self.cluster(clusters[0]);
+            }
+
+            var clustersSub = self.cluster.subscribe(function (newCluster) {
+              if (params.onClusterSelect) {
+                params.onClusterSelect(newCluster);
+              }
+              apiHelper.setInTotalStorage('contextSelector', 'lastSelectedCluster', newCluster);
+
+              // TODO: Adjust computes and namespaces when cluster changes?
+            });
+            self.disposals.push(function () {
+              clustersSub.dispose();
+            })
+          }).always(function () {
+            self.loadingClusters(false);
+          });
+        } else {
+          self.lastClustersPromise = $.Deferred().resolve().promise();
+        }
 
         self.loadingComputes = ko.observable(false);
         self.availableComputes = ko.observableArray();
         self.compute = params.compute;
         self.hideComputes = params.hideComputes || !self.compute;
-        self.hideLabels = params.hideLabels;
 
         if (params.compute) {
           self.loadingComputes(true);
@@ -319,7 +383,7 @@ from desktop.views import _ko
         }
 
         self.loadingContext = ko.pureComputed(function () {
-          return self.loadingNamespaces() || self.loadingComputes() || self.loadingDatabases();
+          return self.loadingClusters() || self.loadingNamespaces() || self.loadingComputes() || self.loadingDatabases();
         });
       };