Эх сурвалжийг харах

HUE-7952 [frontend] Only load comments from Nav for databases, tables and columns

This also makes sure it doesn't try multiple times in case of API error (unless refreshed from assist)
Johan Ahlen 7 жил өмнө
parent
commit
554fae3

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

@@ -1823,6 +1823,8 @@ var ApiHelper = (function () {
       url +=  (options.isView ? '?type=view' : '?type=table') + '&database=' + options.path[0] + '&name=' + options.path[1];
     } else if (options.path.length === 3) {
       url +=  '?type=field&database=' + options.path[0] + '&table=' + options.path[1] + '&name=' + options.path[2];
+    } else {
+      return new CancellablePromise($.Deferred().reject().promise());
     }
 
     var request = self.simplePost(url, {

+ 218 - 18
desktop/core/src/desktop/static/desktop/js/dataCatalog.js

@@ -23,7 +23,7 @@ var DataCatalog = (function () {
   var cacheEnabled = true;
 
   /**
-   * @param {String} sourceType
+   * @param {string} sourceType
    *
    * @constructor
    */
@@ -36,14 +36,25 @@ var DataCatalog = (function () {
     });
   }
 
+  /**
+   * Disables the caching for subsequent operations, mainly used for test purposes
+   */
   DataCatalog.prototype.disableCache = function () {
     cacheEnabled = false;
   };
 
+  /**
+   * Enables the cache for subsequent operations, mainly used for test purposes
+   */
   DataCatalog.prototype.enableCache = function () {
     cacheEnabled = true;
   };
 
+  /**
+   * Clears the data catalog and cache for the given path and any children thereof.
+   *
+   * @param {string[]} rootPath - The path to clear
+   */
   DataCatalog.prototype.clearStorageCascade = function (rootPath) {
     var self = this;
     var deferred = $.Deferred();
@@ -77,6 +88,11 @@ var DataCatalog = (function () {
     return $.when.apply($, deletePromises);
   };
 
+  /**
+   * Updates the cache for the given entry
+   *
+   * @param {DataCatalogEntry} dataCatalogEntry
+   */
   DataCatalog.prototype.updateStore = function (dataCatalogEntry) {
     var self = this;
     if (!cacheEnabled) {
@@ -97,8 +113,9 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Loads Navigator Optimizer popularity for multiple tables in one go.
    *
-   * @param {object} options
+   * @param {Object} options
    * @param {string[][]} options.paths
    * @param {boolean} [options.silenceErrors] - Default true
    *
@@ -208,6 +225,12 @@ var DataCatalog = (function () {
     return new CancellablePromise(deferred.promise(), cancellablePromises);
   };
 
+  /**
+   * Helper function to fill a catalog entry with cached metadata.
+   *
+   * @param {DataCatalogEntry} dataCatalogEntry - The entry to fill
+   * @param {Object} storeEntry - The cached version
+   */
   var mergeFromStoreEntry = function (dataCatalogEntry, storeEntry) {
     var mergeAttribute = function (attributeName, ttl, promiseName) {
       if (storeEntry.version === DATA_CATALOG_VERSION && storeEntry[attributeName] && (!storeEntry[attributeName].hueTimestamp || (Date.now() - storeEntry[attributeName].hueTimestamp) < ttl)) {
@@ -270,6 +293,15 @@ var DataCatalog = (function () {
     return deferred.promise();
   };
 
+  /**
+   * Wrapper function around ApiHelper calls, it will also save the entry on success.
+   *
+   * @param {string} apiHelperFunction - The name of the ApiHelper function to call
+   * @param {string} attributeName - The attribute to set
+   * @param {DataCatalogEntry} dataCatalogEntry - The catalog entry
+   * @param {Object} [apiOptions]
+   * @param {boolean} [apiOptions.silenceErrors]
+   */
   var fetchAndSave = function (apiHelperFunction, attributeName, dataCatalogEntry, apiOptions) {
     return ApiHelper.getInstance()[apiHelperFunction]({
       sourceType: dataCatalogEntry.getSourceType(),
@@ -278,10 +310,14 @@ var DataCatalog = (function () {
     }).done(function (data) {
       dataCatalogEntry[attributeName] = data;
       dataCatalogEntry.saveLater();
+    }).fail(function () {
+      dataCatalogEntry[attributeName] = {};
     })
   };
 
   /**
+   * Helper function to reload the source meta for the given entry
+   *
    * @param {DataCatalogEntry} dataCatalogEntry
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors]
@@ -304,6 +340,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Helper function to reload the navigator meta for the given entry
+   *
    * @param {DataCatalogEntry} dataCatalogEntry
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors] - Default true
@@ -311,7 +349,7 @@ var DataCatalog = (function () {
    * @return {CancellablePromise}
    */
   var reloadNavigatorMeta = function (dataCatalogEntry, apiOptions) {
-    if (HAS_NAVIGATOR && (dataCatalogEntry.getSourceType() === 'hive' || dataCatalogEntry.getSourceType() === 'impala')) {
+    if (dataCatalogEntry.canHaveNavigatorMetadata()) {
       dataCatalogEntry.navigatorMetaPromise = fetchAndSave('fetchNavigatorMetadata', 'navigatorMeta', dataCatalogEntry, apiOptions);
     } else {
       dataCatalogEntry.navigatorMetaPromise =  $.Deferred.reject().promise();
@@ -320,6 +358,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Helper function to reload the analysis for the given entry
+   *
    * @param {DataCatalogEntry} dataCatalogEntry
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors]
@@ -333,11 +373,11 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Helper function to reload the sample for the given entry
+   *
    * @param {DataCatalogEntry} dataCatalogEntry
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors]
-   * @param {boolean} [apiOptions.cachedOnly]
-   * @param {boolean} [apiOptions.refreshCache]
    *
    * @return {CancellablePromise}
    */
@@ -347,6 +387,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Helper function to reload the nav opt metadata for the given entry
+   *
    * @param {DataCatalogEntry} dataCatalogEntry
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors] - Default true
@@ -365,7 +407,7 @@ var DataCatalog = (function () {
   /**
    * @param {DataCatalog} dataCatalog
    * @param {string|string[]} path
-   * @param {Object} definition - Initial known metadata on creation
+   * @param {Object} definition - Initial known metadata on creation (normally comes from the parent entry)
    *
    * @constructor
    */
@@ -450,8 +492,6 @@ var DataCatalog = (function () {
       invalidatePromise = $.Deferred().resolve().promise();
     }
 
-
-
     self.reset();
     var saveDeferred = cascade ? self.dataCatalog.clearStorageCascade(self.path) : self.save();
 
@@ -487,6 +527,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Get the children of the catalog entry, columns for a table entry etc.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors]
    * @param {boolean} [options.cachedOnly]
@@ -569,6 +611,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Loads navigator metdata for children, only applicable to databases and tables
+   *
    * @param {Object} [options]
    * @param {boolean} [options.refreshCache]
    * @param {boolean} [options.silenceErrors] - Default true
@@ -586,7 +630,7 @@ var DataCatalog = (function () {
       options.silenceErrors = true;
     }
 
-    if (!HAS_NAVIGATOR || (self.getSourceType() !== 'hive' && self.getSourceType() !== 'impala')) {
+    if (!self.canHaveNavigatorMetadata() || self.isField()) {
       return $.Deferred().reject().promise();
     }
 
@@ -643,6 +687,13 @@ var DataCatalog = (function () {
     return self.navigatorMetaForChildrenPromise;
   };
 
+  /**
+   * Helper function used when loading navopt metdata for children
+   *
+   * @param {Object} response
+   * @param {Object} [options]
+   * @param {boolean} [options.silenceErrors]
+   */
   DataCatalogEntry.prototype.applyNavOptResponseToChildren = function (response, options) {
     var self = this;
     var deferred = $.Deferred();
@@ -703,6 +754,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Loads nav opt popularity for the children of this entry.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.refreshCache]
    * @param {boolean} [options.silenceErrors] - Default true
@@ -745,6 +798,18 @@ var DataCatalog = (function () {
     return self.navOptPopularityForChildrenPromise;
   };
 
+  /**
+   * Returns true if the catalog entry can have navigator metadata
+   *
+   * @return {boolean}
+   */
+  DataCatalogEntry.prototype.canHaveNavigatorMetadata = function () {
+    var self = this;
+    return HAS_NAVIGATOR
+      && (self.getSourceType() === 'hive' || self.getSourceType() === 'impala')
+      && self.isDatabase() || self.isTableOrView() || self.isColumn();
+  };
+
   /**
    * Returns the currently known comment without loading any additional metadata
    *
@@ -758,16 +823,23 @@ var DataCatalog = (function () {
     return self.sourceMeta && self.sourceMeta.comment || '';
   };
 
+  /**
+   * Checks whether the comment is known and has been loaded from the proper source
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.hasResolvedComment = function () {
     var self = this;
-    if (HAS_NAVIGATOR && (self.getSourceType() === 'hive' || self.getSourceType() === 'impala')) {
+    if (self.canHaveNavigatorMetadata()) {
       return typeof self.navigatorMeta !== 'undefined';
     }
     return typeof self.sourceMeta !== 'undefined';
   };
 
   /**
-   * @param {Object|boolean} [apiOptions] -
+   * Gets the comment for this entry, fetching it if necessary from the proper source.
+   *
+   * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors]
    * @param {boolean} [apiOptions.cachedOnly]
    * @param {boolean} [apiOptions.refreshCache]
@@ -789,7 +861,7 @@ var DataCatalog = (function () {
       }
     };
 
-    if (HAS_NAVIGATOR && (self.getSourceType() === 'hive' || self.getSourceType() === 'impala')) {
+    if (self.canHaveNavigatorMetadata()) {
       if (self.navigatorMeta) {
         deferred.resolve(self.navigatorMeta.description || self.navigatorMeta.originalDescription || '');
       } else {
@@ -809,6 +881,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Sets the comment in the proper source
+   *
    * @param {string} comment
    * @param {Object} [apiOptions]
    * @param {boolean} [apiOptions.silenceErrors]
@@ -821,7 +895,7 @@ var DataCatalog = (function () {
     var self = this;
     var deferred = $.Deferred();
 
-    if (HAS_NAVIGATOR && (self.getSourceType() === 'hive' || self.getSourceType() === 'impala')) {
+    if (self.canHaveNavigatorMetadata()) {
       self.getNavigatorMeta(apiOptions).done(function (navigatorMeta) {
         if (navigatorMeta) {
           ApiHelper.getInstance().updateNavigatorMetadata({
@@ -869,7 +943,7 @@ var DataCatalog = (function () {
   DataCatalogEntry.prototype.addNavigatorTags = function (tags) {
     var self = this;
     var deferred = $.Deferred();
-    if (HAS_NAVIGATOR) {
+    if (self.canHaveNavigatorMetadata()) {
       self.getNavigatorMeta().done(function (navMeta) {
         if (navMeta && typeof navMeta.identity !== 'undefined') {
         ApiHelper.getInstance().addNavTags(navMeta.identity, tags).done(function (response) {
@@ -902,7 +976,7 @@ var DataCatalog = (function () {
   DataCatalogEntry.prototype.deleteNavigatorTags = function (tags) {
     var self = this;
     var deferred = $.Deferred();
-    if (HAS_NAVIGATOR) {
+    if (self.canHaveNavigatorMetadata()) {
       self.getNavigatorMeta().done(function (navMeta) {
         if (navMeta && typeof navMeta.identity !== 'undefined') {
           ApiHelper.getInstance().deleteNavTags(navMeta.identity, tags).done(function (response) {
@@ -925,6 +999,11 @@ var DataCatalog = (function () {
     return deferred.promise();
   };
 
+  /**
+   * Checks if the entry can have children or not without fetching additional metadata.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.hasPossibleChildren = function () {
     var self = this;
     return (self.path.length < 3) ||
@@ -933,36 +1012,71 @@ var DataCatalog = (function () {
       (self.definition && /^(?:struct|array|map)/i.test(self.definition.type));
   };
 
+  /**
+   * Returns the index representing the order in which the backend returned this entry.
+   *
+   * @return {number}
+   */
   DataCatalogEntry.prototype.getIndex = function () {
     var self = this;
     return self.definition && self.definition.index ? self.definition.index : 0;
   };
 
+  /**
+   * Returns the source type of this entry.
+   *
+   * @return {string} - 'impala', 'hive', 'solr', etc.
+   */
   DataCatalogEntry.prototype.getSourceType = function () {
     var self = this;
     return self.dataCatalog.sourceType;
-  }
+  };
 
+  /**
+   * Returns true if the entry represents a data source.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isSource = function () {
     var self = this;
     return self.path.length === 0;
   };
 
+  /**
+   * Returns true if the entry is a database.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isDatabase = function () {
     var self = this;
     return self.path.length === 1;
   };
 
+  /**
+   * Returns true if the entry is a table or a view.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isTableOrView = function () {
     var self = this;
     return self.path.length === 2;
   };
 
+  /**
+   * Returns the default tooltip to use for the entry, either the comment if known or the qualified path.
+   *
+   * @return {string}
+   */
   DataCatalogEntry.prototype.getTooltip = function () {
     var self = this;
     return self.getResolvedComment() || self.getTitle();
   };
 
+  /**
+   * Returns the default title used for the entry, the qualified path with type for fields.
+   *
+   * @return {string}
+   */
   DataCatalogEntry.prototype.getTitle = function () {
     var self = this;
     var title = self.getQualifiedPath();
@@ -975,11 +1089,22 @@ var DataCatalog = (function () {
     return title;
   };
 
+  /**
+   * Returns the fully qualified path for this entry.
+   *
+   * @return {string}
+   */
   DataCatalogEntry.prototype.getQualifiedPath = function () {
     var self = this;
     return self.path.join('.');
-  }
+  };
 
+  /**
+   * Returns the display name for the entry, name or qualified path plus type for fields
+   *
+   * @param {boolean} qualified - Whether to use the qualified path or not, default false
+   * @return {string}
+   */
   DataCatalogEntry.prototype.getDisplayName = function (qualified) {
     var self = this;
     var displayName = qualified ? self.getQualifiedPath() : self.name;
@@ -992,16 +1117,33 @@ var DataCatalog = (function () {
     return displayName;
   };
 
+  /**
+   * Returns true for columns that are a primary key. Note that the definition has to come from a parent entry, i.e.
+   * getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isPrimaryKey = function () {
     var self = this;
     return self.isColumn() && self.definition && /true/i.test(self.definition.primary_key);
   };
 
+  /**
+   * Returns true if the entry is a partition key. Note that the definition has to come from a parent entry, i.e.
+   * getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isPartitionKey = function () {
     var self = this;
     return self.definition && !!self.definition.partitionKey;
   };
 
+  /**
+   * Returns true if the entry is a table. It will be accurate once the source meta has been loaded.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isTable = function () {
     var self = this;
     if (self.path.length === 2) {
@@ -1016,6 +1158,11 @@ var DataCatalog = (function () {
     return false;
   };
 
+  /**
+   * Returns true if the entry is a table. It will be accurate once the source meta has been loaded.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isView = function () {
     var self = this;
     return self.path.length === 2 &&
@@ -1023,11 +1170,22 @@ var DataCatalog = (function () {
       (self.definition && self.definition.type && self.definition.type.toLowerCase() === 'view'));
   };
 
+  /**
+   * Returns true if the entry is a column.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isColumn = function () {
     var self = this;
     return self.path.length === 3;
   };
 
+  /**
+   * Returns true if the entry is a column. It will be accurate once the source meta has been loaded or if loaded from
+   * a parent entry via getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isComplex = function () {
     var self = this;
     return self.path.length > 2 && (
@@ -1035,28 +1193,59 @@ var DataCatalog = (function () {
       (self.definition && /^(?:struct|array|map)/i.test(self.definition.type)));
   };
 
+  /**
+   * Returns true if the entry is a field, i.e. column or child of a complex type.
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isField = function () {
     var self = this;
     return self.path.length > 2;
   };
 
+  /**
+   * Returns true if the entry is an array. It will be accurate once the source meta has been loaded or if loaded from
+   * a parent entry via getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isArray = function () {
     var self = this;
     return (self.sourceMeta && /^array/i.test(self.sourceMeta.type)) ||
       (self.definition && /^array/i.test(self.definition.type));
   };
 
+  /**
+   * Returns true if the entry is a map. It will be accurate once the source meta has been loaded or if loaded from
+   * a parent entry via getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isMap = function () {
     var self = this;
     return (self.sourceMeta && /^map/i.test(self.sourceMeta.type)) ||
       (self.definition && /^map/i.test(self.definition.type));
   };
 
+  /**
+   * Returns true if the entry is a map value. It will be accurate once the source meta has been loaded or if loaded
+   * from a parent entry via getChildren().
+   *
+   * @return {boolean}
+   */
   DataCatalogEntry.prototype.isMapValue = function () {
     var self = this;
     return self.definition && self.definition.isMapValue;
   };
 
+  /**
+   * Returns the type of the entry. It will be accurate once the source meta has been loaded or if loaded from
+   * a parent entry via getChildren().
+   *
+   * For complex entries the type definition is stripped to either 'array', 'map' or 'struct'
+   *
+   * @return {string}
+   */
   DataCatalogEntry.prototype.getType = function () {
     var self = this;
     var type = self.sourceMeta && self.sourceMeta.type || self.definition.type || '';
@@ -1067,6 +1256,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Gets the source metadata for the entry. It will fetch it if not cached or if the refresh option is set.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors]
    * @param {boolean} [options.cachedOnly]
@@ -1086,6 +1277,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Gets the analysis for the entry. It will fetch it if not cached or if the refresh option is set.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors]
    * @param {boolean} [options.cachedOnly]
@@ -1106,6 +1299,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Gets the Navigator metadata for the entry. It will fetch it if not cached or if the refresh option is set.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors] - Default true
    * @param {boolean} [options.cachedOnly]
@@ -1135,6 +1330,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Gets the Nav Opt metadata for the entry. It will fetch it if not cached or if the refresh option is set.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors] - Default true
    * @param {boolean} [options.cachedOnly]
@@ -1164,6 +1361,8 @@ var DataCatalog = (function () {
   };
 
   /**
+   * Gets the sample for the entry. It will fetch it if not cached or if the refresh option is set.
+   *
    * @param {Object} [options]
    * @param {boolean} [options.silenceErrors]
    * @param {boolean} [options.cachedOnly]
@@ -1185,8 +1384,9 @@ var DataCatalog = (function () {
   var instances = {};
 
   /**
-   * @param {string} sourceType
+   * Helepr function to get the DataCatalog instance for a given data source.
    *
+   * @param {string} sourceType
    * @return {DataCatalog}
    */
   var getCatalog = function (sourceType) {

+ 1 - 1
desktop/core/src/desktop/templates/hue_ace_autocompleter.mako

@@ -669,7 +669,7 @@ from desktop.views import _ko
     <!-- /ko -->
     <!-- /ko -->
     <!-- ko if: loading -->
-    <!-- ko hueSpinner: { spin: loading, size: 'small', inline: true } --><!-- /ko -->
+    <div class="details-comment" ><!-- ko hueSpinner: { spin: loading, size: 'small', inline: true } --><!-- /ko --></div>
     <!-- /ko -->
     <!-- ko ifnot: loading -->
     <!-- ko if: comment() -->