Преглед на файлове

[frontend] Add a complete sql-scratchpad web component

This component contains the editor, execute actions, progress bar and the result table in one component
Johan Åhlén преди 4 години
родител
ревизия
4704ac24fc

+ 48 - 0
desktop/core/src/desktop/js/apps/editor/components/sqlScratchpad/SqlScratchpad.scss

@@ -0,0 +1,48 @@
+/*
+ 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.
+*/
+
+@import 'desktop/core/src/desktop/js/components/styles/mixins';
+
+.sql-scratchpad {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  .sql-scratchpad-container {
+    @include fillAbsolute;
+    @include display-flex;
+    @include flex-direction(column);
+    overflow: hidden;
+
+    .sql-scratchpad-editor {
+      @include flex(0 1 50%);
+    }
+
+    .sql-scratchpad-progress {
+      @include flex(0 0 3px);
+    }
+
+    .sql-scratchpad-actions {
+      @include flex(0 0 25px);
+    }
+
+    .sql-scratchpad-result {
+      @include flex(0 1 50%);
+    }
+  }
+}

+ 181 - 0
desktop/core/src/desktop/js/apps/editor/components/sqlScratchpad/SqlScratchpad.vue

@@ -0,0 +1,181 @@
+<!--
+  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 class="sql-scratchpad">
+    <HueIcons />
+    <Spinner v-if="loading" spin="true" />
+    <div v-if="!loading && executor" class="sql-scratchpad-container">
+      <div class="sql-scratchpad-editor">
+        <AceEditor
+          :id="id"
+          :ace-options="aceOptions"
+          :executor="executor"
+          :sql-parser-provider="sqlParserProvider"
+          :sql-reference-provider="sqlReferenceProvider"
+          @active-statement-changed="onActiveStatementChanged"
+        />
+      </div>
+      <div class="sql-scratchpad-progress">
+        <ExecutableProgressBar :executable="activeExecutable" />
+      </div>
+      <div class="sql-scratchpad-actions">
+        <ExecuteButton :executable="activeExecutable" />
+        <ExecuteLimitInput :executable="activeExecutable" />
+      </div>
+      <div class="sql-scratchpad-result">
+        <ResultTable :executable="activeExecutable" />
+      </div>
+    </div>
+    <div v-else-if="!loading && !executor">
+      Failed loading the SQL Scratchpad!
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+  import { defineComponent, onMounted, PropType, ref, toRefs } from 'vue';
+  import { Ace } from 'ext/ace';
+
+  import genericAutocompleteParser from 'parse/sql/generic/genericAutocompleteParser';
+  import genericSyntaxParser from 'parse/sql/generic/genericSyntaxParser';
+  import { SqlParserProvider } from 'parse/types';
+  import { SqlReferenceProvider } from 'sql/reference/types';
+
+  import './SqlScratchpad.scss';
+  import AceEditor from '../aceEditor/AceEditor.vue';
+  import { ActiveStatementChangedEventDetails } from '../aceEditor/types';
+  import ExecutableProgressBar from '../ExecutableProgressBar.vue';
+  import ExecuteButton from '../ExecuteButton.vue';
+  import ExecuteLimitInput from '../ExecuteLimitInput.vue';
+  import ResultTable from '../result/ResultTable.vue';
+  import Executor from '../../execution/executor';
+  import SqlExecutable from '../../execution/sqlExecutable';
+  import contextCatalog from 'catalog/contextCatalog';
+  import HueIcons from 'components/icons/HueIcons.vue';
+  import Spinner from 'components/Spinner.vue';
+  import { findEditorConnector, getConfig } from 'config/hueConfig';
+  import { Compute, Connector, Namespace } from 'config/types';
+  import { UUID } from 'utils/hueUtils';
+
+  export default defineComponent({
+    name: 'SqlScratchpad',
+    components: {
+      Spinner,
+      HueIcons,
+      ResultTable,
+      ExecuteLimitInput,
+      ExecuteButton,
+      ExecutableProgressBar,
+      AceEditor
+    },
+    props: {
+      dialect: {
+        type: String as PropType<string | null>,
+        default: null
+      }
+    },
+    setup(props) {
+      const { dialect } = toRefs(props);
+      const activeExecutable = ref<SqlExecutable | null>(null);
+      const executor = ref<Executor | null>(null);
+      const loading = ref<boolean>(true);
+      const id = UUID();
+
+      const sqlParserProvider: SqlParserProvider = {
+        getAutocompleteParser: () => Promise.resolve(genericAutocompleteParser),
+        getSyntaxParser: () => Promise.resolve(genericSyntaxParser)
+      };
+
+      const sqlReferenceProvider: SqlReferenceProvider = {
+        getReservedKeywords: () => Promise.resolve(new Set<string>()),
+        getSetOptions: () => Promise.resolve({}),
+        getUdfCategories: () => Promise.resolve([]),
+        hasUdfCategories: () => false
+      };
+
+      const aceOptions: Ace.Options = {
+        showLineNumbers: true,
+        showGutter: true,
+        maxLines: null,
+        minLines: null
+      };
+
+      const initializeExecutor = async (): Promise<void> => {
+        try {
+          await getConfig();
+        } catch {
+          console.warn('Failed loading Hue config!');
+          return;
+        }
+
+        const connector = findEditorConnector(
+          connector => !dialect.value || connector.dialect === dialect.value
+        );
+        if (!connector) {
+          console.warn('No connector found!');
+          return;
+        }
+
+        try {
+          const { namespaces } = await contextCatalog.getNamespaces({ connector });
+
+          if (!namespaces.length || !namespaces[0].computes.length) {
+            console.warn('No namespaces or computes found!');
+            return;
+          }
+
+          const namespace = namespaces[0];
+          const compute = namespace.computes[0];
+
+          executor.value = new Executor({
+            connector: (() => connector as Connector) as KnockoutObservable<Connector>,
+            namespace: (() => namespace) as KnockoutObservable<Namespace>,
+            compute: (() => compute) as KnockoutObservable<Compute>,
+            database: (() => 'default') as KnockoutObservable<string>
+          });
+        } catch {}
+      };
+
+      const onActiveStatementChanged = (event: ActiveStatementChangedEventDetails) => {
+        if (executor.value) {
+          executor.value.update(event, false);
+          activeExecutable.value = executor.value.activeExecutable as SqlExecutable;
+        }
+      };
+
+      onMounted(async () => {
+        loading.value = true;
+        try {
+          await initializeExecutor();
+        } catch {}
+        loading.value = false;
+      });
+
+      return {
+        aceOptions,
+        activeExecutable,
+        executor,
+        id,
+        onActiveStatementChanged,
+        sqlParserProvider,
+        sqlReferenceProvider
+      };
+    }
+  });
+</script>

+ 23 - 0
desktop/core/src/desktop/js/apps/editor/components/sqlScratchpad/SqlScratchpadWebComponent.d.ts

@@ -0,0 +1,23 @@
+// 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.
+
+declare const _default: {
+  login(username: string, password: string): Promise<void>;
+  setBaseUrl(baseUrl: string): void;
+  setBearerToken(bearerToken: string): void;
+};
+
+export default _default;

+ 31 - 0
desktop/core/src/desktop/js/apps/editor/components/sqlScratchpad/SqlScratchpadWebComponent.ts

@@ -0,0 +1,31 @@
+// 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.
+
+import SqlScratchpad from './SqlScratchpad.vue';
+import { wrap } from 'vue/webComponentWrap';
+import { post, setBaseUrl, setBearerToken } from 'api/utils';
+import 'utils/json.bigDataParse';
+
+wrap('sql-scratchpad', SqlScratchpad);
+
+const login = async (username: string, password: string): Promise<void> =>
+  post('iam/v1/get/auth-token/', { username, password });
+
+export default {
+  login,
+  setBaseUrl,
+  setBearerToken
+};

+ 8 - 1
webpack.config.npm.js

@@ -93,7 +93,10 @@ const hueConfigLibConfig = Object.assign({}, defaultConfig, {
 const webComponentsConfig = Object.assign({}, defaultConfig, {
   entry: {
     ErDiagram: [`${JS_ROOT}/components/er-diagram/webcomp.ts`],
-    QueryEditorWebComponents: [`${JS_ROOT}/apps/editor/components/QueryEditorWebComponents.ts`]
+    QueryEditorWebComponents: [`${JS_ROOT}/apps/editor/components/QueryEditorWebComponents.ts`],
+    SqlScratchpadWebComponent: [
+      `${JS_ROOT}/apps/editor/components/sqlScratchpad/SqlScratchpadWebComponent.ts`
+    ]
   },
   output: {
     path: `${DIST_DIR}/lib/components`,
@@ -108,6 +111,10 @@ const webComponentsConfig = Object.assign({}, defaultConfig, {
         {
           from: `${JS_ROOT}/apps/editor/components/QueryEditorWebComponents.d.ts`,
           to: `${DIST_DIR}/lib/components`
+        },
+        {
+          from: `${JS_ROOT}/apps/editor/components/sqlScratchpad/SqlScratchpadWebComponent.d.ts`,
+          to: `${DIST_DIR}/lib/components`
         }
       ]
     })