浏览代码

[frontend] Expose the hueConfig lib and enable custom base url

Johan Ahlen 4 年之前
父节点
当前提交
05d4f09d85

+ 63 - 0
desktop/core/src/desktop/js/config/hueConfig.d.ts

@@ -0,0 +1,63 @@
+// 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 {
+  AppType,
+  BrowserInterpreter,
+  DashboardInterpreter,
+  EditorInterpreter,
+  HueConfig,
+  Interpreter
+} from './types';
+
+export declare const REFRESH_CONFIG_EVENT = 'cluster.config.refresh.config';
+export declare const CONFIG_REFRESHED_EVENT = 'cluster.config.set.config';
+export declare const GET_KNOWN_CONFIG_EVENT = 'cluster.config.get.config';
+
+export declare const refreshConfig: () => Promise<HueConfig>;
+export declare const getLastKnownConfig: () => HueConfig | undefined;
+export declare const findDashboardConnector: (
+  connectorTest: (connector: Interpreter) => boolean
+) => DashboardInterpreter | undefined;
+export declare const findBrowserConnector: (
+  connectorTest: (connector: Interpreter) => boolean
+) => BrowserInterpreter | undefined;
+export declare const findEditorConnector: (
+  connectorTest: (connector: Interpreter) => boolean
+) => EditorInterpreter | undefined;
+export declare const filterEditorConnectors: (
+  connectorTest: (connector: Interpreter) => boolean
+) => EditorInterpreter[] | undefined;
+
+/**
+ * This takes the initial path from the "browser" config, used in cases where the users can't access '/'
+ * for abfs etc.
+ */
+export declare const getRootFilePath: (connector: BrowserInterpreter) => string;
+
+declare const _default: {
+  refreshConfig: (hueBaseUrl?: string) => Promise<HueConfig>;
+  getInterpreters: (appType: AppType) => Interpreter[];
+  getLastKnownConfig: () => HueConfig;
+  getRootFilePath: (connector: BrowserInterpreter) => string;
+  findBrowserConnector: (connectorTest: (connector: Interpreter) => boolean) => BrowserInterpreter;
+  findDashboardConnector: (
+    connectorTest: (connector: Interpreter) => boolean
+  ) => DashboardInterpreter;
+  findEditorConnector: (connectorTest: (connector: Interpreter) => boolean) => EditorInterpreter;
+};
+
+export default _default;

+ 16 - 7
desktop/core/src/desktop/js/config/hueConfig.ts

@@ -14,8 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { simplePostAsync } from 'api/apiUtils';
-import { FETCH_CONFIG_API } from 'api/urls';
+import { post } from 'api/utils';
 import {
   AppType,
   BrowserInterpreter,
@@ -26,6 +25,8 @@ import {
 } from './types';
 import huePubSub from 'utils/huePubSub';
 
+const FETCH_CONFIG_API = '/desktop/api2/get_config/';
+
 export const REFRESH_CONFIG_EVENT = 'cluster.config.refresh.config';
 export const CONFIG_REFRESHED_EVENT = 'cluster.config.set.config';
 export const GET_KNOWN_CONFIG_EVENT = 'cluster.config.get.config';
@@ -33,13 +34,11 @@ export const GET_KNOWN_CONFIG_EVENT = 'cluster.config.get.config';
 let lastConfigPromise: Promise<HueConfig> | undefined;
 let lastKnownConfig: HueConfig | undefined;
 
-const fetchConfig = async (): Promise<HueConfig> =>
-  await simplePostAsync(FETCH_CONFIG_API, {}, { silenceErrors: true });
-
-export const refreshConfig = async (): Promise<HueConfig> => {
+export const refreshConfig = async (hueBaseUrl?: string): Promise<HueConfig> => {
   lastConfigPromise = new Promise<HueConfig>(async (resolve, reject) => {
     try {
-      const apiResponse = await fetchConfig();
+      const url = hueBaseUrl ? hueBaseUrl + FETCH_CONFIG_API : FETCH_CONFIG_API;
+      const apiResponse = await post<HueConfig>(url, {}, { silenceErrors: true });
       if (apiResponse.status == 0) {
         lastKnownConfig = apiResponse;
         resolve(lastKnownConfig);
@@ -127,3 +126,13 @@ huePubSub.subscribe(GET_KNOWN_CONFIG_EVENT, (callback?: (appConfig: HueConfig) =
     lastConfigPromise.then(callback).catch(callback);
   }
 });
+
+export default {
+  refreshConfig,
+  getInterpreters,
+  getLastKnownConfig,
+  getRootFilePath,
+  findBrowserConnector,
+  findDashboardConnector,
+  findEditorConnector
+};

+ 3 - 3
desktop/core/src/desktop/js/ko/components/assist/ko.assistFunctionsPanel.test.js

@@ -15,7 +15,7 @@
 // limitations under the License.
 import * as ko from 'knockout';
 
-import * as apiUtils from 'api/apiUtils';
+import * as apiUtils from 'api/utils';
 import * as refApiUtils from 'sql/reference/apiUtils';
 import AssistFunctionsPanel from './ko.assistFunctionsPanel';
 import { refreshConfig } from 'config/hueConfig';
@@ -25,7 +25,7 @@ describe('ko.assistFunctionsPanel.js', () => {
   jest.spyOn(refApiUtils, 'fetchUdfs').mockImplementation(() => Promise.resolve([]));
 
   it('should handle cluster config updates', async () => {
-    const spy = jest.spyOn(apiUtils, 'simplePostAsync').mockImplementation(async () =>
+    const spy = jest.spyOn(apiUtils, 'post').mockImplementation(async () =>
       Promise.resolve({
         status: 0,
         app_config: {
@@ -58,7 +58,7 @@ describe('ko.assistFunctionsPanel.js', () => {
 
     spy.mockRestore();
 
-    const changeSpy = jest.spyOn(apiUtils, 'simplePostAsync').mockImplementation(async () =>
+    const changeSpy = jest.spyOn(apiUtils, 'post').mockImplementation(async () =>
       Promise.resolve({
         status: 0,
         app_config: {

+ 3 - 3
desktop/core/src/desktop/js/ko/components/assist/ko.assistLangRefPanel.test.js

@@ -16,7 +16,7 @@
 
 import * as ko from 'knockout';
 
-import * as apiUtils from 'api/apiUtils';
+import * as apiUtils from 'api/utils';
 import AssistLangRefPanel from './ko.assistLangRefPanel';
 import { refreshConfig } from 'config/hueConfig';
 import { sleep } from 'utils/hueUtils';
@@ -28,7 +28,7 @@ describe('ko.assistLangRefPanel.js', () => {
   });
 
   it('should handle cluster config updates', async () => {
-    const spy = jest.spyOn(apiUtils, 'simplePostAsync').mockImplementation(async () =>
+    const spy = jest.spyOn(apiUtils, 'post').mockImplementation(async () =>
       Promise.resolve({
         status: 0,
         app_config: {
@@ -48,7 +48,7 @@ describe('ko.assistLangRefPanel.js', () => {
 
     spy.mockRestore();
 
-    const changeSpy = jest.spyOn(apiUtils, 'simplePostAsync').mockImplementation(async () =>
+    const changeSpy = jest.spyOn(apiUtils, 'post').mockImplementation(async () =>
       Promise.resolve({
         status: 0,
         app_config: {

+ 40 - 27
tools/examples/components/sql-scratchpad/src/components/SqlScratchpad.tsx

@@ -1,7 +1,7 @@
 import React, {FC, useState} from 'react';
 
 import hueComponents from 'gethue/lib/components/QueryEditorWebComponents';
-
+import hueConfig from 'gethue/lib/config/hueConfig';
 import Executor from 'gethue/lib/execution/executor';
 
 import { QueryEditor } from './QueryEditor';
@@ -10,36 +10,49 @@ import { ExecuteProgress } from './ExecuteProgress';
 import { ResultTable } from './ResultTable';
 import SqlExecutable from 'gethue/src/apps/editor/execution/sqlExecutable';
 
-hueComponents.configure({
-  baseUrl: 'http://localhost:1234/'
-});
+const HUE_BASE_URL = 'http://localhost:8888/'
 
-const executor = new Executor({
-  compute: (() => ({ id: 'default' })) as KnockoutObservable<any>,
-  connector: (() => ({
-    dialect: 'hive',
-    id: 'hive',
-    is_sql: true
-  })) as KnockoutObservable<any>,
-  database: (() => 'default') as KnockoutObservable<any>,
-  namespace: (() => ({ id: 'default' })) as KnockoutObservable<any>,
+hueComponents.configure({
+  baseUrl: HUE_BASE_URL
 });
 
 export const SqlScratchpad: FC = () => {
   const [activeExecutable, setActiveExecutable] = useState<SqlExecutable | undefined>(undefined);
+  const [executor, setExecutor] = useState<Executor | undefined>(undefined);
+
+  React.useEffect(() => {
+    console.info('Refreshing config');
+    hueConfig.refreshConfig(HUE_BASE_URL).then(() => {
+      const connector = hueConfig.findEditorConnector(() => true); // Returns the first connector
+
+      setExecutor(new Executor({
+        compute: (() => ({ id: 'default' })) as KnockoutObservable<any>,
+        connector: (() => connector) as KnockoutObservable<any>,
+        database: (() => 'default') as KnockoutObservable<any>,
+        namespace: (() => ({ id: 'default' })) as KnockoutObservable<any>,
+      }));
+    }).catch(err => {
+      console.warn('Failed loading the Hue config')
+    })
+  })
+
+  if (executor) {
+    return <React.Fragment>
+      <div className="ace-editor">
+        <QueryEditor executor={executor} setActiveExecutable={setActiveExecutable}/>
+      </div>
+      <div className="executable-progress-bar">
+        <ExecuteProgress activeExecutable={activeExecutable}/>
+      </div>
+      <div className="executable-actions">
+        <ExecuteActions activeExecutable={activeExecutable}/>
+      </div>
+      <div className="result-table">
+        <ResultTable/>
+      </div>
+    </React.Fragment>
+  } else {
+    return <div>Loading Config...</div>
+  }
 
-  return <React.Fragment>
-    <div className="ace-editor">
-      <QueryEditor executor={executor} setActiveExecutable={setActiveExecutable}/>
-    </div>
-    <div className="executable-progress-bar">
-      <ExecuteProgress activeExecutable={activeExecutable}/>
-    </div>
-    <div className="executable-actions">
-      <ExecuteActions activeExecutable={activeExecutable}/>
-    </div>
-    <div className="result-table">
-      <ResultTable/>
-    </div>
-  </React.Fragment>
 };

+ 33 - 3
webpack.config.npm.js

@@ -23,6 +23,7 @@ const { VueLoaderPlugin } = require('vue-loader');
 
 const DIST_DIR = path.join(__dirname, 'npm_dist');
 const JS_ROOT = path.join(__dirname, '/desktop/core/src/desktop/js');
+const WRAPPER_DIR = `${__dirname}/tools/vue3-webcomponent-wrapper`;
 
 const defaultConfig = Object.assign({}, require('./webpack.config'), {
   mode: 'production',
@@ -32,7 +33,7 @@ const defaultConfig = Object.assign({}, require('./webpack.config'), {
   plugins: []
 });
 
-const libConfig = Object.assign({}, defaultConfig, {
+const executorLibConfig = Object.assign({}, defaultConfig, {
   entry: {
     executor: [`${JS_ROOT}/apps/editor/execution/executor.ts`]
   },
@@ -60,6 +61,30 @@ const libConfig = Object.assign({}, defaultConfig, {
   ]
 });
 
+const hueConfigLibConfig = Object.assign({}, defaultConfig, {
+  entry: {
+    hueConfig: [`${JS_ROOT}/config/hueConfig.ts`]
+  },
+  output: {
+    path: `${DIST_DIR}/lib/config`,
+    library: '[name]',
+    libraryExport: 'default',
+    libraryTarget: 'umd',
+    umdNamedDefine: true,
+    globalObject: `(typeof self !== 'undefined' ? self : this)`
+  },
+  plugins: [
+    new CopyWebpackPlugin({
+      patterns: [
+        {
+          from: `${JS_ROOT}/config/hueConfig.d.ts`,
+          to: `${DIST_DIR}/lib/config`
+        }
+      ]
+    })
+  ]
+});
+
 const webComponentsConfig = Object.assign({}, defaultConfig, {
   entry: {
     ErDiagram: [`${JS_ROOT}/components/er-diagram/webcomp.ts`],
@@ -136,7 +161,6 @@ const parserConfig = Object.assign({}, defaultConfig, {
   }
 });
 
-const WRAPPER_DIR = `${__dirname}/tools/vue3-webcomponent-wrapper`;
 const vue3WebCompWrapperConfig = Object.assign({}, defaultConfig, {
   entry: {
     index: [`${JS_ROOT}/vue/wrapper/index.ts`]
@@ -157,4 +181,10 @@ const vue3WebCompWrapperConfig = Object.assign({}, defaultConfig, {
   ]
 });
 
-module.exports = [libConfig, webComponentsConfig, parserConfig, vue3WebCompWrapperConfig];
+module.exports = [
+  executorLibConfig,
+  hueConfigLibConfig,
+  webComponentsConfig,
+  parserConfig,
+  vue3WebCompWrapperConfig
+];