Bläddra i källkod

[editor] Add the autocomplete join details panel in editor v2

Johan Ahlen 4 år sedan
förälder
incheckning
d751bf9e8a

+ 7 - 0
desktop/core/src/desktop/js/apps/editor/components/aceEditor/AceEditor.scss

@@ -14,6 +14,7 @@
   .hue-ace-syntax-error {
     position: absolute;
     border-bottom: 1px dotted $hue-error-color;
+    border-bottom: 1px dotted $hue-error-color;
     border-radius: 0 !important;
   }
 
@@ -182,6 +183,12 @@
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
+
+    .popular {
+      color: $fluid-orange-300;
+      margin-top: 3px;
+      float: right;
+    }
   }
 
   .autocompleter-header-popularity {

+ 14 - 11
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/AceAutocomplete.vue

@@ -73,7 +73,7 @@
       </div>
     </div>
     <div v-if="detailsComponent" class="autocompleter-details">
-      <component :is="detailsComponent" :suggestion="focusedEntry" />
+      <component :is="detailsComponent" :suggestion="focusedEntry" :connector="connector" />
     </div>
   </div>
 </template>
@@ -82,6 +82,7 @@
   import { Ace } from 'ext/ace';
   import ace from 'ext/aceHelper';
   import { AutocompleteParser } from 'parse/types';
+  import { Connector } from 'types/config';
   import Vue from 'vue';
   import Component from 'vue-class-component';
   import { Prop, Watch } from 'vue-property-decorator';
@@ -94,11 +95,12 @@
   import I18n from 'utils/i18n';
 
   import AutocompleteResults, { Suggestion } from './AutocompleteResults';
-  import CatalogEntryDetailsPanel from './CatalogEntryDetailsPanel.vue';
   import MatchedText from './MatchedText.vue';
-  import OptionDetailsPanel from './OptionDetailsPanel.vue';
   import SqlAutocompleter from './SqlAutocompleter';
-  import UdfDetailsPanel from './UdfDetailsPanel.vue';
+  import CatalogEntryDetailsPanel from './details/CatalogEntryDetailsPanel.vue';
+  import JoinDetailsPanel from './details/JoinDetailsPanel.vue';
+  import OptionDetailsPanel from './details/OptionDetailsPanel.vue';
+  import UdfDetailsPanel from './details/UdfDetailsPanel.vue';
   import Spinner from 'components/Spinner.vue';
   import { clickOutsideDirective } from 'components/directives/clickOutsideDirective';
   import { SqlReferenceProvider } from 'sql/reference/types';
@@ -111,6 +113,7 @@
   @Component({
     components: {
       CatalogEntryDetailsPanel,
+      JoinDetailsPanel,
       MatchedText,
       OptionDetailsPanel,
       Spinner,
@@ -285,19 +288,19 @@
       this.subTracker.dispose();
     }
 
+    get connector(): Connector | undefined {
+      if (this.executor) {
+        return this.executor.connector();
+      }
+    }
+
     get detailsComponent(): string | undefined {
       if (this.focusedEntry && this.focusedEntry.details) {
         if (this.focusedEntry.hasCatalogEntry) {
           return 'CatalogEntryDetailsPanel';
         }
-        if (this.focusedEntry.category.categoryId === CategoryId.UDF) {
-          return 'UdfDetailsPanel';
-        }
-        if (this.focusedEntry.category.categoryId === CategoryId.Option) {
-          return 'OptionDetailsPanel';
-        }
+        return this.focusedEntry.category.detailsComponent;
       }
-      return undefined;
     }
 
     get filtered(): Suggestion[] {

+ 1 - 1
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/AutocompleteResults.ts

@@ -14,8 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { Category, CategoryInfo } from './Category';
 import { CancellablePromise } from 'api/cancellablePromise';
-import { Category, CategoryInfo } from 'apps/editor/components/aceEditor/autocomplete/Category';
 import Executor from 'apps/editor/execution/executor';
 import DataCatalogEntry, {
   FieldSample,

+ 97 - 93
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/Category.ts

@@ -20,21 +20,22 @@ import I18n from 'utils/i18n';
 export interface CategoryInfo {
   categoryId: CategoryId;
   color: string;
+  detailsComponent?: string;
   label: string;
-  weight?: number;
   popular?: boolean;
+  weight?: number;
 }
 
 enum Colors {
-  Popular = '#61bbff',
-  Keyword = '#0074d2',
   Column = '#2fae2f',
-  Table = '#ffa139',
   Database = '#517989',
-  Sample = '#fea7a7',
+  Files = '#9e1414',
   IdentCteVar = '#ca4f01',
-  UDF = '#acfbac',
-  Files = '#9e1414'
+  Keyword = '#0074d2',
+  Popular = '#61bbff',
+  Sample = '#fea7a7',
+  Table = '#ffa139',
+  UDF = '#acfbac'
 }
 
 export enum CategoryId {
@@ -68,6 +69,55 @@ export const Category: { [categoryId in keyof typeof CategoryId]: CategoryInfo }
     color: '#90ceff',
     label: I18n('All')
   },
+  ColRefKeyword: {
+    categoryId: CategoryId.ColRefKeyword,
+    color: Colors.Keyword,
+    label: I18n('Keywords'),
+    weight: 100
+  },
+  Column: {
+    categoryId: CategoryId.Column,
+    color: Colors.Column,
+    label: I18n('Columns'),
+    weight: 1000
+  },
+  CTE: {
+    categoryId: CategoryId.CTE,
+    color: Colors.IdentCteVar,
+    label: I18n('CTEs'),
+    weight: 700
+  },
+  Database: {
+    categoryId: CategoryId.Database,
+    color: Colors.Database,
+    label: I18n('Databases'),
+    weight: 500
+  },
+  Files: {
+    categoryId: CategoryId.Files,
+    color: Colors.Files,
+    label: I18n('Files'),
+    weight: 300
+  },
+  Identifier: {
+    categoryId: CategoryId.Identifier,
+    color: Colors.IdentCteVar,
+    label: I18n('Identifiers'),
+    weight: 800
+  },
+  Keyword: {
+    categoryId: CategoryId.Keyword,
+    color: Colors.Keyword,
+    label: I18n('Keywords'),
+    weight: 0
+  },
+  Option: {
+    categoryId: CategoryId.Option,
+    color: Colors.UDF,
+    detailsComponent: 'OptionDetailsPanel',
+    label: I18n('Options'),
+    weight: 400
+  },
   Popular: {
     categoryId: CategoryId.Popular,
     color: Colors.Popular,
@@ -76,129 +126,83 @@ export const Category: { [categoryId in keyof typeof CategoryId]: CategoryInfo }
   },
   PopularAggregate: {
     categoryId: CategoryId.PopularAggregate,
-    weight: 1500,
     color: Colors.Popular,
     label: I18n('Popular'),
-    popular: true
+    popular: true,
+    weight: 1500
   },
-  PopularGroupBy: {
-    categoryId: CategoryId.PopularGroupBy,
-    weight: 1300,
+  PopularActiveJoin: {
+    categoryId: CategoryId.PopularActiveJoin,
     color: Colors.Popular,
     label: I18n('Popular'),
-    popular: true
+    popular: true,
+    weight: 1500
   },
-  PopularOrderBy: {
-    categoryId: CategoryId.PopularOrderBy,
-    weight: 1200,
+  PopularFilter: {
+    categoryId: CategoryId.PopularFilter,
     color: Colors.Popular,
     label: I18n('Popular'),
-    popular: true
+    popular: true,
+    weight: 1400
   },
-  PopularFilter: {
-    categoryId: CategoryId.PopularFilter,
-    weight: 1400,
+  PopularGroupBy: {
+    categoryId: CategoryId.PopularGroupBy,
     color: Colors.Popular,
     label: I18n('Popular'),
-    popular: true
+    popular: true,
+    weight: 1300
   },
-  PopularActiveJoin: {
-    categoryId: CategoryId.PopularActiveJoin,
-    weight: 1500,
+  PopularJoin: {
+    categoryId: CategoryId.PopularJoin,
     color: Colors.Popular,
+    detailsComponent: 'JoinDetailsPanel',
     label: I18n('Popular'),
-    popular: true
+    weight: 1500
   },
   PopularJoinCondition: {
     categoryId: CategoryId.PopularJoinCondition,
-    weight: 1500,
     color: Colors.Popular,
     label: I18n('Popular'),
-    popular: true
+    popular: true,
+    weight: 1500
   },
-  Column: {
-    categoryId: CategoryId.Column,
-    weight: 1000,
-    color: Colors.Column,
-    label: I18n('Columns')
+  PopularOrderBy: {
+    categoryId: CategoryId.PopularOrderBy,
+    color: Colors.Popular,
+    label: I18n('Popular'),
+    popular: true,
+    weight: 1200
   },
   Sample: {
     categoryId: CategoryId.Sample,
-    weight: 900,
     color: Colors.Sample,
-    label: I18n('Samples')
-  },
-  Identifier: {
-    categoryId: CategoryId.Identifier,
-    weight: 800,
-    color: Colors.IdentCteVar,
-    label: I18n('Identifiers')
-  },
-  CTE: {
-    categoryId: CategoryId.CTE,
-    weight: 700,
-    color: Colors.IdentCteVar,
-    label: I18n('CTEs')
+    label: I18n('Samples'),
+    weight: 900
   },
   Table: {
     categoryId: CategoryId.Table,
-    weight: 600,
     color: Colors.Table,
-    label: I18n('Tables')
-  },
-  Database: {
-    categoryId: CategoryId.Database,
-    weight: 500,
-    color: Colors.Database,
-    label: I18n('Databases')
+    label: I18n('Tables'),
+    weight: 600
   },
   UDF: {
     categoryId: CategoryId.UDF,
-    weight: 400,
+    detailsComponent: 'UdfDetailsPanel',
     color: Colors.UDF,
-    label: I18n('UDFs')
-  },
-  Option: {
-    categoryId: CategoryId.Option,
-    weight: 400,
-    color: Colors.UDF,
-    label: I18n('Options')
-  },
-  Files: {
-    categoryId: CategoryId.Files,
-    weight: 300,
-    color: Colors.Files,
-    label: I18n('Files')
-  },
-  VirtualColumn: {
-    categoryId: CategoryId.VirtualColumn,
-    weight: 200,
-    color: Colors.Column,
-    label: I18n('Columns')
-  },
-  ColRefKeyword: {
-    categoryId: CategoryId.ColRefKeyword,
-    weight: 100,
-    color: Colors.Keyword,
-    label: I18n('Keywords')
+    label: I18n('UDFs'),
+    weight: 400
   },
   Variable: {
     categoryId: CategoryId.Variable,
-    weight: 50,
     color: Colors.IdentCteVar,
-    label: I18n('Variables')
-  },
-  Keyword: {
-    categoryId: CategoryId.Keyword,
-    weight: 0,
-    color: Colors.Keyword,
-    label: I18n('Keywords')
+    label: I18n('Variables'),
+    weight: 50
   },
-  PopularJoin: {
-    categoryId: CategoryId.PopularJoin,
-    weight: 1500,
-    color: Colors.Popular,
-    label: I18n('Popular')
+  VirtualColumn: {
+    categoryId: CategoryId.VirtualColumn,
+    color: Colors.Column,
+    label: I18n('Columns'),
+    weight: 200
   }
 };
 

+ 1 - 1
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/CatalogEntryDetailsPanel.vue → desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/details/CatalogEntryDetailsPanel.vue

@@ -70,9 +70,9 @@
   import Component from 'vue-class-component';
   import { Prop } from 'vue-property-decorator';
 
+  import { Suggestion } from '../AutocompleteResults';
   import DataCatalogEntry from 'catalog/DataCatalogEntry';
   import I18n from 'utils/i18n';
-  import { Suggestion } from './AutocompleteResults';
 
   import Spinner from 'components/Spinner.vue';
 

+ 67 - 0
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/details/JoinDetailsPanel.vue

@@ -0,0 +1,67 @@
+<!--
+  Licensed to Cloudera, Inc. under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  Cloudera, Inc. licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<template>
+  <div>
+    <div class="autocompleter-header">
+      <i class="fa fa-fw fa-superscript" />
+      <span>{{ I18n('Popular Join') }}</span>
+      <i class="popular fa fa-fw fa-star-o" :title="popularityTitle" />
+    </div>
+    <div class="autocompleter-details-contents">
+      <div class="autocompleter-details-contents-inner">
+        <sql-text :value="suggestion.value" :dialect="dialect" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+  import { Connector } from 'types/config';
+  import Vue from 'vue';
+  import Component from 'vue-class-component';
+  import { Prop } from 'vue-property-decorator';
+
+  import { Suggestion } from '../AutocompleteResults';
+  import { TopJoinValue } from 'catalog/MultiTableEntry';
+  import SqlText from 'components/SqlText.vue';
+  import I18n from 'utils/i18n';
+
+  @Component({
+    components: { SqlText },
+    methods: { I18n }
+  })
+  export default class JoinDetailsPanel extends Vue {
+    @Prop({ required: true })
+    suggestion!: Suggestion;
+    @Prop({ required: false })
+    connector?: Connector;
+
+    get details(): TopJoinValue {
+      return <TopJoinValue>this.suggestion.details;
+    }
+
+    get dialect(): string | undefined {
+      return this.connector && this.connector.dialect;
+    }
+
+    get popularityTitle(): string {
+      return `${this.details.relativePopularity || '?'}%`;
+    }
+  }
+</script>

+ 4 - 3
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/OptionDetailsPanel.vue → desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/details/OptionDetailsPanel.vue

@@ -34,13 +34,14 @@
 </template>
 
 <script lang="ts">
-  import { SetDetails } from 'sql/reference/types';
-  import I18n from 'utils/i18n';
-  import { Suggestion } from './AutocompleteResults';
   import Vue from 'vue';
   import Component from 'vue-class-component';
   import { Prop } from 'vue-property-decorator';
 
+  import { Suggestion } from '../AutocompleteResults';
+  import { SetDetails } from 'sql/reference/types';
+  import I18n from 'utils/i18n';
+
   @Component({
     methods: { I18n }
   })

+ 3 - 2
desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/UdfDetailsPanel.vue → desktop/core/src/desktop/js/apps/editor/components/aceEditor/autocomplete/details/UdfDetailsPanel.vue

@@ -32,12 +32,13 @@
 </template>
 
 <script lang="ts">
-  import { UdfDetails } from 'sql/reference/types';
-  import { Suggestion } from './AutocompleteResults';
   import Vue from 'vue';
   import Component from 'vue-class-component';
   import { Prop } from 'vue-property-decorator';
 
+  import { UdfDetails } from 'sql/reference/types';
+  import { Suggestion } from '../AutocompleteResults';
+
   @Component
   export default class UdfDetailsPanel extends Vue {
     @Prop({ required: true })

+ 1 - 0
desktop/core/src/desktop/js/catalog/MultiTableEntry.ts

@@ -26,6 +26,7 @@ import { Connector } from 'types/config';
 import { hueWindow } from 'types/types';
 
 export interface TopJoinValue {
+  totalTableCount: number;
   totalQueryCount: number;
   joinType: string;
   tables: string[];