Forráskód Böngészése

[editor] Move suggestions and loading logic to the AceAutocomplete Vue component

This takes care of issues with reactivity when the filter doesn't change between subsequent autocompletions.
Johan Ahlen 5 éve
szülő
commit
a935ed671f

+ 36 - 53
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/autocomplete/AceAutocomplete.vue

@@ -81,6 +81,7 @@
 <script lang="ts">
   import { Ace } from 'ext/ace';
   import ace from 'ext/aceHelper';
+  import hueDebug from 'utils/hueDebug';
   import Vue from 'vue';
   import Component from 'vue-class-component';
   import { Prop } from 'vue-property-decorator';
@@ -90,7 +91,6 @@
   import SubscriptionTracker from 'components/utils/SubscriptionTracker';
   import sqlUtils, { SortOverride } from 'sql/sqlUtils';
   import huePubSub from 'utils/huePubSub';
-  import { defer } from 'utils/hueUtils';
   import I18n from 'utils/i18n';
 
   import AutocompleteResults, { Suggestion } from './AutocompleteResults';
@@ -128,6 +128,7 @@
     @Prop({ required: false, default: false })
     temporaryOnly?: boolean;
 
+    loading = false;
     active = false;
     filter = '';
     availableCategories = [Category.All];
@@ -140,6 +141,7 @@
     sortOverride?: SortOverride | null = null;
     autocompleter?: SqlAutocompleter;
     autocompleteResults?: AutocompleteResults;
+    suggestions: Suggestion[] = [];
 
     changeTimeout = -1;
     positionInterval = -1;
@@ -198,14 +200,6 @@
 
       this.autocompleteResults = this.autocompleter.autocompleteResults;
 
-      this.subTracker.subscribe('hue.ace.autocompleter.done', () => {
-        defer(() => {
-          if (this.active && !this.filtered.length && !this.loading) {
-            this.detach();
-          }
-        });
-      });
-
       this.subTracker.subscribe(
         'hue.ace.autocompleter.show',
         async (details: {
@@ -224,31 +218,41 @@
 
           this.positionAutocompleteDropdown();
 
-          const afterAutocomplete = () => {
-            newBase.$insertRight = true;
-            this.base = newBase;
-            if (this.autocompleteResults) {
-              this.filter = prefix;
-            }
-            this.active = true;
-            this.selectedIndex = 0;
-          };
-
-          if (
-            !this.active ||
-            !this.base ||
-            newBase.column !== this.base.column ||
-            newBase.row !== this.base.row
-          ) {
+          if (this.active) {
+            this.detach();
+          }
+
+          if (!this.base || newBase.column !== this.base.column || newBase.row !== this.base.row) {
             try {
-              await this.autocompleter.autocomplete();
-              afterAutocomplete();
-              this.attach();
+              this.loading = true;
+              const parseResult = await this.autocompleter.autocomplete();
+              if (hueDebug.showParseResult) {
+                // eslint-disable-next-line no-restricted-syntax
+                console.log(parseResult);
+              }
+
+              if (parseResult) {
+                this.suggestions = [];
+                this.autocompleteResults.update(parseResult, this.suggestions).finally(() => {
+                  this.loading = false;
+                });
+
+                this.selectedIndex = 0;
+                newBase.$insertRight = true;
+                this.base = newBase;
+                if (this.autocompleteResults) {
+                  this.filter = prefix;
+                }
+                this.active = true;
+                this.attach();
+              }
             } catch (err) {
-              afterAutocomplete();
+              if (typeof console.warn !== 'undefined') {
+                console.warn(err);
+              }
+              this.active = false;
+              this.detach();
             }
-          } else {
-            afterAutocomplete();
           }
         }
       );
@@ -286,7 +290,7 @@
         return [];
       }
 
-      let result = this.autocompleteResults.entries;
+      let result = this.suggestions;
 
       if (this.filter) {
         result = sqlUtils.autocompleteFilter(this.filter, result);
@@ -339,27 +343,6 @@
       return undefined;
     }
 
-    get loading(): boolean {
-      return (
-        !this.autocompleteResults ||
-        this.autocompleteResults.loadingKeywords ||
-        this.autocompleteResults.loadingFunctions ||
-        this.autocompleteResults.loadingDatabases ||
-        this.autocompleteResults.loadingTables ||
-        this.autocompleteResults.loadingColumns ||
-        this.autocompleteResults.loadingValues ||
-        this.autocompleteResults.loadingPaths ||
-        this.autocompleteResults.loadingJoins ||
-        this.autocompleteResults.loadingJoinConditions ||
-        this.autocompleteResults.loadingAggregateFunctions ||
-        this.autocompleteResults.loadingGroupBys ||
-        this.autocompleteResults.loadingOrderBys ||
-        this.autocompleteResults.loadingFilters ||
-        this.autocompleteResults.loadingPopularTables ||
-        this.autocompleteResults.loadingPopularColumns
-      );
-    }
-
     get visible(): boolean {
       return this.active && (this.loading || !!this.filtered.length);
     }

+ 8 - 80
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/autocomplete/AutocompleteResults.ts

@@ -45,7 +45,6 @@ import dataCatalog from 'catalog/dataCatalog';
 import { SetDetails, UdfDetails } from 'sql/reference/types';
 import { hueWindow } from 'types/types';
 import hueUtils from 'utils/hueUtils';
-import huePubSub from 'utils/huePubSub';
 import I18n from 'utils/i18n';
 import sqlUtils from 'sql/sqlUtils';
 import { matchesType } from 'sql/reference/typeUtils';
@@ -144,28 +143,11 @@ class AutocompleteResults {
   activeDatabase: string;
 
   parseResult!: AutocompleteParseResult;
-  entries: Suggestion[] = [];
   subTracker = new SubscriptionTracker();
   onCancelFunctions: (() => void)[] = [];
   lastKnownRequests: JQueryXHR[] = [];
   cancellablePromises: CancellableJqPromise<unknown>[] = [];
 
-  loadingKeywords = false;
-  loadingFunctions = false;
-  loadingDatabases = false;
-  loadingTables = false;
-  loadingColumns = false;
-  loadingValues = false;
-  loadingPaths = false;
-  loadingJoins = false;
-  loadingJoinConditions = false;
-  loadingAggregateFunctions = false;
-  loadingGroupBys = false;
-  loadingOrderBys = false;
-  loadingFilters = false;
-  loadingPopularTables = false;
-  loadingPopularColumns = false;
-
   constructor(options: { executor: Executor; editor: Ace.Editor; temporaryOnly: boolean }) {
     this.executor = options.executor;
     this.editor = options.editor;
@@ -177,7 +159,7 @@ class AutocompleteResults {
     return this.executor.connector().dialect || this.executor.connector().type;
   }
 
-  async update(parseResult: AutocompleteParseResult): Promise<void> {
+  async update(parseResult: AutocompleteParseResult, suggestions: Suggestion[]): Promise<void[]> {
     let cancelFn;
     while ((cancelFn = this.onCancelFunctions.pop())) {
       cancelFn();
@@ -185,24 +167,6 @@ class AutocompleteResults {
     this.activeDatabase = parseResult.useDatabase || this.executor.database();
     this.parseResult = parseResult;
 
-    this.entries = [];
-
-    this.loadingKeywords = false;
-    this.loadingFunctions = false;
-    this.loadingDatabases = false;
-    this.loadingTables = false;
-    this.loadingColumns = false;
-    this.loadingValues = false;
-    this.loadingPaths = false;
-    this.loadingJoins = false;
-    this.loadingJoinConditions = false;
-    this.loadingAggregateFunctions = false;
-    this.loadingGroupBys = false;
-    this.loadingOrderBys = false;
-    this.loadingFilters = false;
-    this.loadingPopularTables = false;
-    this.loadingPopularColumns = false;
-
     if (this.parseResult.udfArgument) {
       await this.adjustForUdfArgument();
     }
@@ -213,9 +177,9 @@ class AutocompleteResults {
       const wrapped = new Promise<void>(resolve => {
         this.onCancelFunctions.push(resolve);
         promise
-          .then(suggestions => {
-            if (suggestions && suggestions.length) {
-              this.entries = [...this.entries, ...suggestions];
+          .then(newSuggestions => {
+            if (newSuggestions && newSuggestions.length) {
+              suggestions.push(...newSuggestions);
             }
             resolve();
           })
@@ -252,8 +216,7 @@ class AutocompleteResults {
       trackPromise(this.handlePopularColumns(columnsPromise));
     }
 
-    await Promise.all(promises);
-    huePubSub.publish('hue.ace.autocompleter.done');
+    return Promise.all(promises);
   }
 
   async adjustForUdfArgument(): Promise<void> {
@@ -389,7 +352,6 @@ class AutocompleteResults {
     if (!suggestColRefKeywords) {
       return [];
     }
-    this.loadingKeywords = true;
     // Wait for the column reference type to be resolved to pick the right keywords
     const colRef = await colRefPromise;
     const colRefKeywordSuggestions: Suggestion[] = [];
@@ -408,7 +370,6 @@ class AutocompleteResults {
         });
       }
     });
-    this.loadingKeywords = false;
     return colRefKeywordSuggestions;
   }
 
@@ -516,7 +477,6 @@ class AutocompleteResults {
       return [];
     }
 
-    this.loadingFunctions = true;
     let suggestions: Suggestion[] = [];
     if (
       suggestFunctions.types &&
@@ -587,7 +547,6 @@ class AutocompleteResults {
       } catch (err) {}
     }
 
-    this.loadingFunctions = false;
     return suggestions;
   }
 
@@ -596,7 +555,6 @@ class AutocompleteResults {
     if (!suggestDatabases) {
       return [];
     }
-    this.loadingDatabases = true;
     const databaseSuggestions: Suggestion[] = [];
     try {
       let prefix = suggestDatabases.prependQuestionMark ? '? ' : '';
@@ -625,7 +583,6 @@ class AutocompleteResults {
       }
     } catch (err) {}
 
-    this.loadingDatabases = false;
     return databaseSuggestions;
   }
 
@@ -634,7 +591,6 @@ class AutocompleteResults {
     if (!suggestTables) {
       return [];
     }
-    this.loadingTables = true;
 
     const getTableSuggestions = async (): Promise<Suggestion[]> => {
       let prefix = suggestTables.prependQuestionMark ? '? ' : '';
@@ -726,7 +682,6 @@ class AutocompleteResults {
       tableSuggestions = await getTableSuggestions();
     }
 
-    this.loadingTables = false;
     return tableSuggestions;
   }
 
@@ -742,7 +697,6 @@ class AutocompleteResults {
     if (!suggestColumns) {
       return [];
     }
-    this.loadingColumns = true;
 
     const columnSuggestions: Suggestion[] = [];
     // For multiple tables we need to merge and make sure identifiers are unique
@@ -789,7 +743,6 @@ class AutocompleteResults {
       });
     }
 
-    this.loadingColumns = false;
     return columnSuggestions;
   }
 
@@ -1078,7 +1031,6 @@ class AutocompleteResults {
       });
     }
 
-    this.loadingValues = true;
     const colRef = await colRefPromise;
 
     if (colRef.samples) {
@@ -1098,7 +1050,6 @@ class AutocompleteResults {
       });
     }
 
-    this.loadingValues = false;
     return valueSuggestions;
   }
 
@@ -1107,7 +1058,6 @@ class AutocompleteResults {
     if (!suggestHdfs) {
       return [];
     }
-    this.loadingPaths = true;
 
     let suggestions: Suggestion[] = [];
 
@@ -1174,7 +1124,6 @@ class AutocompleteResults {
             weightAdjust: 0,
             popular: false
           });
-          this.loadingPaths = false;
           return suggestions;
         }
       }
@@ -1218,7 +1167,6 @@ class AutocompleteResults {
       );
     });
 
-    this.loadingPaths = false;
     return suggestions;
   }
 
@@ -1245,7 +1193,6 @@ class AutocompleteResults {
     if (!(<hueWindow>window).HAS_OPTIMIZER || !suggestJoins) {
       return [];
     }
-    this.loadingJoins = true;
 
     const paths = this.tableIdentifierChainsToPaths(suggestJoins.tables);
     if (!paths.length) {
@@ -1358,7 +1305,6 @@ class AutocompleteResults {
       }
     } catch (err) {}
 
-    this.loadingJoins = false;
     return joinSuggestions;
   }
 
@@ -1367,7 +1313,6 @@ class AutocompleteResults {
     if (!(<hueWindow>window).HAS_OPTIMIZER || !suggestJoinConditions) {
       return [];
     }
-    this.loadingJoinConditions = true;
 
     const paths = this.tableIdentifierChainsToPaths(suggestJoinConditions.tables);
     if (!paths.length) {
@@ -1447,7 +1392,6 @@ class AutocompleteResults {
       }
     } catch (err) {}
 
-    this.loadingJoinConditions = true;
     return joinConditionSuggestions;
   }
 
@@ -1461,8 +1405,6 @@ class AutocompleteResults {
       return [];
     }
 
-    this.loadingAggregateFunctions = true;
-
     const paths = this.tableIdentifierChainsToPaths(suggestAggregateFunctions.tables);
     if (!paths.length) {
       return [];
@@ -1575,7 +1517,6 @@ class AutocompleteResults {
       });
     } catch (err) {}
 
-    this.loadingAggregateFunctions = false;
     return aggregateFunctionsSuggestions;
   }
 
@@ -1682,14 +1623,12 @@ class AutocompleteResults {
     if (!(<hueWindow>window).HAS_OPTIMIZER || !suggestGroupBys) {
       return [];
     }
-    this.loadingGroupBys = true;
-    const suggestions = await this.handlePopularGroupByOrOrderBy(
+
+    return await this.handlePopularGroupByOrOrderBy(
       'groupByColumn',
       suggestGroupBys,
       columnsPromise
     );
-    this.loadingGroupBys = false;
-    return suggestions;
   }
 
   async handleOrderBys(columnsPromise: Promise<Suggestion[]>): Promise<Suggestion[]> {
@@ -1697,14 +1636,11 @@ class AutocompleteResults {
     if (!(<hueWindow>window).HAS_OPTIMIZER || !suggestOrderBys) {
       return [];
     }
-    this.loadingOrderBys = true;
-    const suggestions = await this.handlePopularGroupByOrOrderBy(
+    return await this.handlePopularGroupByOrOrderBy(
       'orderByColumn',
       suggestOrderBys,
       columnsPromise
     );
-    this.loadingOrderBys = false;
-    return suggestions;
   }
 
   async handleFilters(): Promise<Suggestion[]> {
@@ -1712,7 +1648,6 @@ class AutocompleteResults {
     if (!(<hueWindow>window).HAS_OPTIMIZER || !suggestFilters) {
       return [];
     }
-    this.loadingFilters = true;
 
     const paths = this.tableIdentifierChainsToPaths(suggestFilters.tables);
     if (!paths.length) {
@@ -1792,7 +1727,6 @@ class AutocompleteResults {
       });
     } catch (err) {}
 
-    this.loadingFilters = false;
     return filterSuggestions;
   }
 
@@ -1802,8 +1736,6 @@ class AutocompleteResults {
       return [];
     }
 
-    this.loadingPopularTables = true;
-
     const db =
       suggestTables.identifierChain &&
       suggestTables.identifierChain.length === 1 &&
@@ -1863,7 +1795,6 @@ class AutocompleteResults {
       }
     } catch (err) {}
 
-    this.loadingPopularTables = false;
     return [];
   }
 
@@ -1883,8 +1814,6 @@ class AutocompleteResults {
       return [];
     }
 
-    this.loadingPopularColumns = true;
-
     try {
       const paths: string[][] = [];
       suggestColumns.tables.forEach(table => {
@@ -1966,7 +1895,6 @@ class AutocompleteResults {
       }
     } catch (err) {}
 
-    this.loadingPopularColumns = false;
     return [];
   }
 

+ 2 - 19
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/autocomplete/SqlAutocompleter.ts

@@ -27,7 +27,6 @@ import { ParsedSqlStatement } from 'parse/sqlStatementsParser';
 import { AutocompleteParser, AutocompleteParseResult } from 'parse/types';
 import { EditorInterpreter } from 'types/config';
 import AutocompleteResults from './AutocompleteResults';
-import hueDebug from 'utils/hueDebug';
 import huePubSub from 'utils/huePubSub';
 import sqlParserRepository from 'parse/sql/sqlParserRepository';
 
@@ -147,7 +146,7 @@ export default class SqlAutocompleter implements Disposable {
     });
   }
 
-  async autocomplete(): Promise<void> {
+  async autocomplete(): Promise<AutocompleteParseResult | undefined> {
     let parseResult;
     try {
       huePubSub.publish(GET_ACTIVE_LOCATIONS_EVENT, (locations: ActiveStatementChangedEvent) => {
@@ -176,23 +175,7 @@ export default class SqlAutocompleter implements Disposable {
       }
     }
 
-    if (!parseResult) {
-      // This prevents Ace from inserting garbled text in case of exception
-      huePubSub.publish('hue.ace.autocompleter.done');
-    } else {
-      if (typeof hueDebug !== 'undefined' && hueDebug.showParseResult) {
-        // eslint-disable-next-line no-restricted-syntax
-        console.log(parseResult);
-      }
-      try {
-        await this.autocompleteResults.update(parseResult);
-      } catch (e) {
-        if (typeof console.warn !== 'undefined') {
-          console.warn(e);
-        }
-        huePubSub.publish('hue.ace.autocompleter.done');
-      }
-    }
+    return parseResult;
   }
 
   dispose(): void {