Browse Source

HUE-8330 [editor] Add query execution analysis to the right assist

Johan Ahlen 7 years ago
parent
commit
5a54f92287

File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue-embedded.css


File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue.css


File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue3-extra.css


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

@@ -1951,12 +1951,40 @@ var ApiHelper = (function () {
     return new CancellablePromise(deferred, request);
   };
 
+  /**
+   * @param {Object} options
+   * @param {boolean} [options.silenceErrors]
+   * @param {string} options.computeId
+   * @param {string} options.queryId
+   * @return {Promise}
+   */
+  ApiHelper.prototype.fetchQueryExecutionAnalysis = function (options)  {
+    var self = this;
+    var url = '/metadata/api/workload_analytics/get_impala_query/';
+    return self.simplePost(url, {
+      'cluster_id': '"' + options.computeId + '"',
+      'query_id': '"' + options.queryId + '"'
+    }, options);
+  };
+
+  /**
+   * @param {Object} options
+   * @param {boolean} [options.silenceErrors]
+   * @param {string} options.sourceType
+   * @return {Promise}
+   */
   ApiHelper.prototype.fetchContextNamespaces = function (options) {
     var self = this;
     var url = '/desktop/api2/context/namespaces/' + options.sourceType;
     return self.simpleGet(url, undefined, options);
   };
 
+  /**
+   * @param {Object} options
+   * @param {boolean} [options.silenceErrors]
+   * @param {string} options.sourceType
+   * @return {Promise}
+   */
   ApiHelper.prototype.fetchContextComputes = function (options) {
     var self = this;
     var url = '/desktop/api2/context/computes/' + options.sourceType;

+ 11 - 7
desktop/core/src/desktop/static/desktop/less/hue-assist.less

@@ -570,22 +570,26 @@
   white-space: nowrap;
 }
 
-.assist-flex-fill {
+.assist-flex-fill,
+.assist-flex-half,
+.assist-flex-quarter {
   position: relative;
-  .flex(1 1 100%);
   white-space: nowrap;
   overflow-x: hidden;
   overflow-y: auto;
   outline: none !important;
 }
 
+.assist-flex-fill {
+  .flex(1 1 100%);
+}
+
 .assist-flex-half {
-  position: relative;
   .flex(1 1 50%);
-  white-space: nowrap;
-  overflow-x: hidden;
-  overflow-y: auto;
-  outline: none !important;
+}
+
+.assist-flex-quarter {
+  .flex(1 1 25%);
 }
 
 .database-tree ul {

+ 55 - 5
desktop/core/src/desktop/templates/assist.mako

@@ -26,7 +26,7 @@ from dashboard.conf import HAS_SQL_ENABLED
 
 from desktop import appmanager
 from desktop import conf
-from desktop.conf import IS_EMBEDDED, USE_NEW_SIDE_PANELS, VCS
+from desktop.conf import IS_EMBEDDED, USE_NEW_SIDE_PANELS, VCS, IS_MULTICLUSTER_ONLY
 from desktop.lib.i18n import smart_unicode
 from desktop.views import _ko
 %>
@@ -2405,8 +2405,8 @@ from desktop.views import _ko
         </div>
 
         <!-- ko if: HAS_OPTIMIZER && !isSolr() -->
-        <div class="assist-flex-header assist-divider"><div class="assist-inner-header">${ _('Suggestions') }</div></div>
-        <div class="assist-flex-half">
+        <div class="assist-flex-header assist-divider"><div class="assist-inner-header">${ _('Query Analysis') }</div></div>
+        <div data-bind="css: IS_MULTICLUSTER_ONLY ? 'assist-flex-quarter' : 'assist-flex-half'">
           <!-- ko if: ! activeRisks().hints -->
           <div class="assist-no-entries">${ _('Select a query or start typing to get optimization hints.') }</div>
           <!-- /ko -->
@@ -2436,10 +2436,37 @@ from desktop.views import _ko
           <!-- /ko -->
         </div>
         <!-- /ko -->
+
+        <!-- ko if: IS_MULTICLUSTER_ONLY && !isSolr() -->
+          <div class="assist-flex-header" data-bind="css: { 'assist-divider': !HAS_OPTIMIZER }"><div class="assist-inner-header">${ _('Execution Analysis') }</div></div>
+          <div data-bind="css: HAS_OPTIMIZER ? 'assist-flex-quarter' : 'assist-flex-half'">
+          <!-- ko hueSpinner: { spin: loadingExecutionAnalysis, inline: true} --><!-- /ko -->
+            <!-- ko ifnot: loadingExecutionAnalysis -->
+            <!-- ko if: !executionAnalysis() -->
+            <div class="assist-no-entries">${ _('Execute a query to get query execution analysis.') }</div>
+            <!-- /ko -->
+            <!-- ko with: executionAnalysis -->
+            <ul class="risk-list" data-bind="foreach: healthChecks">
+              <li data-bind="templatePopover : { placement: 'left', contentTemplate: 'health-check-details-content', titleTemplate: 'health-check-details-title', minWidth: '320px', trigger: 'hover' }">
+                <div class="risk-list-title risk-list-normal"><span data-bind="text: name"></span></div>
+              </li>
+            </ul>
+            <!-- /ko -->
+          <!-- /ko -->
+          </div>
+        <!-- /ko -->
       </div>
     </div>
   </script>
 
+  <script type="text/html" id="health-check-details-content">
+    <div data-bind="text: description"></div>
+  </script>
+
+  <script type="text/html" id="health-check-details-title">
+    <span data-bind="text: name"></span>
+  </script>
+
   <script type="text/javascript">
     var AssistantUtils = (function () {
           return {
@@ -2510,6 +2537,9 @@ from desktop.views import _ko
         self.statementCount = ko.observable(0);
         self.activeStatementIndex = ko.observable(0);
 
+        self.loadingExecutionAnalysis = ko.observable(false);
+        self.executionAnalysis = ko.observable();
+
         self.hasActiveRisks = ko.pureComputed(function () {
            return self.activeRisks().hints && self.activeRisks().hints.length > 0;
         });
@@ -2807,8 +2837,7 @@ from desktop.views import _ko
           }
         };
 
-
-        huePubSub.subscribe('data.catalog.entry.refreshed', function (details) {
+        var entryRefreshedSub = huePubSub.subscribe('data.catalog.entry.refreshed', function (details) {
           var sourceType = details.entry.getSourceType();
           if (sources[sourceType]) {
             var completeRefresh = false;
@@ -2851,8 +2880,29 @@ from desktop.views import _ko
           }
         });
 
+        var clearAnalysisSub = huePubSub.subscribe('assist.clear.execution.analysis', function() {
+          self.executionAnalysis(undefined);
+        });
+
+        var executionAnalysisSub = huePubSub.subscribe('assist.update.execution.analysis', function (details) {
+          self.loadingExecutionAnalysis(true);
+          ApiHelper.getInstance().fetchQueryExecutionAnalysis({
+            silenceErrors: true,
+            computeId: details.computeId,
+            queryId: details.queryId
+          }).done(function (response) {
+            if (response && response.data && response.data.query)
+            self.executionAnalysis(response.data.query)
+          }).always(function () {
+            self.loadingExecutionAnalysis(false);
+          });
+        });
+
         self.disposals.push(function () {
+          entryRefreshedSub.remove();
           activeTabSub.dispose();
+          clearAnalysisSub.remove();
+          executionAnalysisSub.remove();
         });
 
         var activeLocationsSub = huePubSub.subscribe('editor.active.locations', function (activeLocations) {

+ 2 - 0
desktop/core/src/desktop/templates/global_js_constants.mako

@@ -48,6 +48,8 @@
 
   window.HAS_OPTIMIZER = '${ has_optimizer() }' === 'True';
 
+  window.IS_MULTICLUSTER_ONLY = '${ conf.IS_MULTICLUSTER_ONLY.get() }' === 'True';
+
   window.HUE_CONTAINER = '${ IS_EMBEDDED.get() }' === 'True' ? '.hue-embedded-container' : 'body';
 
   window.IS_EMBEDDED = '${ IS_EMBEDDED.get() }' === 'True';

+ 13 - 0
desktop/libs/notebook/src/notebook/static/notebook/js/notebook.ko.js

@@ -1533,6 +1533,10 @@ var EditorViewModel = (function() {
         return;
       }
 
+      if (self.type() === 'impala') {
+        huePubSub.publish('assist.clear.execution.analysis');
+      }
+
       self.status('running');
       self.statusForButtons('executing');
 
@@ -1975,6 +1979,15 @@ var EditorViewModel = (function() {
                 self.checkStatusTimeout = setTimeout(self.checkStatus, delay);
               }
             } else if (self.status() === 'available') {
+              if (self.type() === 'impala') {
+
+                // TODO: Use real compute and query ID
+                huePubSub.publish('assist.update.execution.analysis', {
+                  computeId: '6bfa86a8-55a2-4466-9003-2b222a9be137', // TODO: Compute ID ?
+                  queryId: '56433486cd84d475:3a86f97000000000'
+                });
+
+              }
               self.fetchResult(100);
               self.progress(100);
               if (self.isSqlDialect()) {

Some files were not shown because too many files changed in this diff