diff --git a/web-console/.gitignore b/web-console/.gitignore index 97c05c42e86..812dd27d8e3 100644 --- a/web-console/.gitignore +++ b/web-console/.gitignore @@ -10,7 +10,7 @@ coordinator-console/ pages/ index.html -lib/sql-function-doc.ts +lib/sql-function-doc.js .tscache tscommand-*.tmp.txt diff --git a/web-console/lib/keywords.d.ts b/web-console/lib/keywords.d.ts new file mode 100644 index 00000000000..f4bc7538c4b --- /dev/null +++ b/web-console/lib/keywords.d.ts @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +export const SQL_KEYWORDS: string[]; +export const SQL_EXPRESSION_PARTS: string[]; +export const SQL_CONSTANTS: string[]; +export const SQL_DYNAMICS: string[]; diff --git a/web-console/src/views/query-view/query-input/keywords.ts b/web-console/lib/keywords.js similarity index 85% rename from web-console/src/views/query-view/query-input/keywords.ts rename to web-console/lib/keywords.js index 08832cc2dc1..85e6b7d0226 100644 --- a/web-console/src/views/query-view/query-input/keywords.ts +++ b/web-console/lib/keywords.js @@ -18,7 +18,7 @@ // Hand picked from https://druid.apache.org/docs/latest/querying/sql.html -export const SQL_KEYWORDS: string[] = [ +exports.SQL_KEYWORDS = [ 'EXPLAIN PLAN FOR', 'WITH', 'AS', @@ -36,7 +36,7 @@ export const SQL_KEYWORDS: string[] = [ 'UNION ALL', ]; -export const SQL_EXPRESSION_PARTS: string[] = [ +exports.SQL_EXPRESSION_PARTS = [ 'FILTER', 'END', 'ELSE', @@ -69,6 +69,6 @@ export const SQL_EXPRESSION_PARTS: string[] = [ 'INTERVAL', ]; -export const SQL_CONSTANTS: string[] = ['NULL', 'FALSE', 'TRUE']; +exports.SQL_CONSTANTS = ['NULL', 'FALSE', 'TRUE']; -export const SQL_DYNAMICS: string[] = ['CURRENT_TIMESTAMP', 'CURRENT_DATE']; +exports.SQL_DYNAMICS = ['CURRENT_TIMESTAMP', 'CURRENT_DATE']; diff --git a/web-console/lib/sql-function-doc.d.ts b/web-console/lib/sql-function-doc.d.ts new file mode 100644 index 00000000000..c4c9c34b3a2 --- /dev/null +++ b/web-console/lib/sql-function-doc.d.ts @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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. + */ + +export interface SyntaxDescription { + name: string; + description: string; +} + +export interface FunctionSyntaxDescription extends SyntaxDescription { + arguments: string; +} + +export const SQL_DATA_TYPES: SyntaxDescription[]; +export const SQL_FUNCTIONS: FunctionSyntaxDescription[]; diff --git a/web-console/package-lock.json b/web-console/package-lock.json index 075d4cc7d56..87bb3917c4f 100644 --- a/web-console/package-lock.json +++ b/web-console/package-lock.json @@ -4428,9 +4428,9 @@ "integrity": "sha512-0sYnfUHHMoajaud/i5BHKA12bUxiWEHJ9rxGqVEppFxsEcxef0TZQ5J59lU+UniEBcz/sG5fTESRyS7cOm3tSQ==" }, "druid-query-toolkit": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.23.tgz", - "integrity": "sha512-6wVAGFw1sjLT9U5f7QNaIKCS0VgUfWLn/X8YWf3YQN3awSCxClzFUQnLKnHeIEb7ot0ca4H6axlb7NpzGqmtzA==", + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.3.24.tgz", + "integrity": "sha512-kFvEXAjjNuJYpeRsAzzO/cJ2rr4nHBGTSCAA4UPxyt4pKNZE/OUap7IQbsdnxYmhkHgfjUBGcFteufaVHSn7SA==", "requires": { "tslib": "^1.10.0" } diff --git a/web-console/package.json b/web-console/package.json index d5a954231ea..a221cc8f66b 100644 --- a/web-console/package.json +++ b/web-console/package.json @@ -61,7 +61,7 @@ "d3": "^5.10.1", "d3-array": "^2.3.1", "druid-console": "0.0.2", - "druid-query-toolkit": "^0.3.23", + "druid-query-toolkit": "^0.3.24", "file-saver": "^2.0.2", "has-own-prop": "^2.0.0", "hjson": "^3.1.2", diff --git a/web-console/script/clean b/web-console/script/clean index 81f38571132..0907eb5c6f4 100755 --- a/web-console/script/clean +++ b/web-console/script/clean @@ -17,8 +17,8 @@ # limitations under the License. rm -rf \ - lib/*.css \ - lib/*.ts \ + lib/react-table.css \ + lib/sql-function-doc.js \ node_modules \ coordinator-console \ pages \ diff --git a/web-console/script/create-sql-function-doc.js b/web-console/script/create-sql-function-doc.js index 785e86db740..af94ac22507 100755 --- a/web-console/script/create-sql-function-doc.js +++ b/web-console/script/create-sql-function-doc.js @@ -21,7 +21,7 @@ const fs = require('fs-extra'); const readfile = '../docs/querying/sql.md'; -const writefile = 'lib/sql-function-doc.ts'; +const writefile = 'lib/sql-function-doc.js'; const readDoc = async () => { const data = await fs.readFile(readfile, 'utf-8'); @@ -30,18 +30,19 @@ const readDoc = async () => { const functionDocs = []; const dataTypeDocs = []; for (let line of lines) { - const functionMatch = line.match(/^\|`(.+\(.*\))`\|(.+)\|$/); + const functionMatch = line.match(/^\|`(\w+)(\(.*\))`\|(.+)\|$/); if (functionMatch) { functionDocs.push({ - syntax: functionMatch[1], - description: functionMatch[2], + name: functionMatch[1], + arguments: functionMatch[2], + description: functionMatch[3], }); } const dataTypeMatch = line.match(/^\|([A-Z]+)\|([A-Z]+)\|(.*)\|(.*)\|$/); if (dataTypeMatch) { dataTypeDocs.push({ - syntax: dataTypeMatch[1], + name: dataTypeMatch[1], description: dataTypeMatch[4] || `Druid runtime type: ${dataTypeMatch[2]}`, }); } @@ -81,16 +82,11 @@ const readDoc = async () => { // This file is auto generated and should not be modified -export interface SyntaxDescription { - syntax: string; - description: string; -} +// prettier-ignore +exports.SQL_DATA_TYPES = ${JSON.stringify(dataTypeDocs, null, 2)}; // prettier-ignore -export const SQL_FUNCTIONS: SyntaxDescription[] = ${JSON.stringify(functionDocs, null, 2)}; - -// prettier-ignore -export const SQL_DATE_TYPES: SyntaxDescription[] = ${JSON.stringify(dataTypeDocs, null, 2)}; +exports.SQL_FUNCTIONS = ${JSON.stringify(functionDocs, null, 2)}; `; await fs.writeFile(writefile, content, 'utf-8'); diff --git a/web-console/src/ace-modes/dsql.js b/web-console/src/ace-modes/dsql.js index 38c936a9532..fe0bb3c1752 100644 --- a/web-console/src/ace-modes/dsql.js +++ b/web-console/src/ace-modes/dsql.js @@ -21,6 +21,9 @@ // Originally licensed under the MIT license (https://github.com/thlorenz/brace/blob/master/LICENSE) // This file was modified to make the list of keywords more closely adhere to what is found in DruidSQL +var druidKeywords = require('../../lib/keywords'); +var druidFunctions = require('../../lib/sql-function-doc'); + ace.define( 'ace/mode/dsql_highlight_rules', ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'], @@ -31,20 +34,25 @@ ace.define( var TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules; var SqlHighlightRules = function() { - var keywords = - 'select|from|where|and|or|group|by|order|limit|offset|having|as|case|' + - 'when|else|end|type|on|desc|asc|union|create|table|if|' + - 'foreign|not|references|default|null|inner|cross|drop|grant'; + // Stuff like: 'with|select|from|where|and|or|group|by|order|limit|having|as|case|' + var keywords = druidKeywords.SQL_KEYWORDS.concat(druidKeywords.SQL_EXPRESSION_PARTS) + .join('|') + .replace(/\s/g, '|'); - var builtinConstants = 'true|false'; + // Stuff like: 'true|false' + var builtinConstants = druidKeywords.SQL_CONSTANTS.join('|'); - var builtinFunctions = - 'avg|count|first|last|max|min|sum|ucase|lcase|mid|len|round|rank|now|format|' + - 'coalesce|ifnull|isnull|nvl'; + // Stuff like: 'avg|count|first|last|max|min' + var builtinFunctions = druidKeywords.SQL_DYNAMICS.concat( + druidFunctions.SQL_FUNCTIONS.map(function(f) { + return f.name; + }), + ).join('|'); - var dataTypes = - 'int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp|' + - 'money|real|number|integer'; + // Stuff like: 'int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp' + var dataTypes = druidFunctions.SQL_DATA_TYPES.map(function(f) { + return f.name; + }).join('|'); var keywordMapper = this.createKeywordMapper( { diff --git a/web-console/src/components/show-log/show-log.tsx b/web-console/src/components/show-log/show-log.tsx index 301932abe90..2467340bc02 100644 --- a/web-console/src/components/show-log/show-log.tsx +++ b/web-console/src/components/show-log/show-log.tsx @@ -36,8 +36,6 @@ function removeFirstPartialLine(log: string): string { return lines.join('\n'); } -let interval: number | undefined; - export interface ShowLogProps { endpoint: string; downloadFilename?: string; @@ -53,8 +51,11 @@ export interface ShowLogState { } export class ShowLog extends React.PureComponent { + static CHECK_INTERVAL = 2500; + private showLogQueryManager: QueryManager; - public log = React.createRef(); + private log = React.createRef(); + private interval: number | undefined; constructor(props: ShowLogProps, context: any) { super(props, context); @@ -87,24 +88,40 @@ export class ShowLog extends React.PureComponent { const { status } = this.props; if (status === 'RUNNING') { - interval = Number(setInterval(() => this.showLogQueryManager.runQuery(null), 2000)); + this.addTailer(); } this.showLogQueryManager.runQuery(null); } componentWillUnmount(): void { - if (interval) clearInterval(interval); + this.removeTailer(); + } + + addTailer() { + if (this.interval) return; + this.interval = Number( + setInterval(() => this.showLogQueryManager.runQuery(null), ShowLog.CHECK_INTERVAL), + ); + } + + removeTailer() { + if (!this.interval) return; + clearInterval(this.interval); + delete this.interval; } private handleCheckboxChange = () => { + const { tail } = this.state; + + const nextTail = !tail; this.setState({ - tail: !this.state.tail, + tail: nextTail, }); - if (!this.state.tail) { - interval = Number(setInterval(() => this.showLogQueryManager.runQuery(null), 2000)); + if (nextTail) { + this.addTailer(); } else { - if (interval) clearInterval(interval); + this.removeTailer(); } }; diff --git a/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx b/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx index daaf9410365..129ef827045 100644 --- a/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx +++ b/web-console/src/dialogs/query-history-dialog/query-history-dialog.tsx @@ -75,10 +75,11 @@ export class QueryHistoryDialog extends React.PureComponent< } private handleSelect = () => { - const { queryRecords, setQueryString } = this.props; + const { queryRecords, setQueryString, onClose } = this.props; const { activeTab } = this.state; setQueryString(queryRecords[activeTab].queryString); + onClose(); }; private handleTabChange = (tab: number) => { diff --git a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx index 000cb9a2d8e..6297e0cf9fe 100644 --- a/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx +++ b/web-console/src/dialogs/query-plan-dialog/query-plan-dialog.tsx @@ -148,7 +148,10 @@ export class QueryPlanDialog extends React.PureComponent< @@ -49,7 +49,7 @@ exports[`run button matches snapshot 1`] = ` class="bp3-popover-target" >