web-console: ACE editor refactoring (#16359)
* Move druid-sql completions to dsql mode
* Use font-size 12
* Convert ace-modes to typescript
* Move aceCompleters to class member
* Use namespace imports
diff --git a/web-console/lib/sql-docs.d.ts b/web-console/lib/sql-docs.d.ts
index a5af232..5948206 100644
--- a/web-console/lib/sql-docs.d.ts
+++ b/web-console/lib/sql-docs.d.ts
@@ -16,5 +16,5 @@
* limitations under the License.
*/
-export const SQL_DATA_TYPES: Record<string, [runtime: string, description: string][]>;
+export const SQL_DATA_TYPES: Record<string, [runtime: string, description: string]>;
export const SQL_FUNCTIONS: Record<string, [args: string, description: string][]>;
diff --git a/web-console/src/ace-modes/__snapshots__/make-doc-html.spec.ts.snap b/web-console/src/ace-modes/__snapshots__/make-doc-html.spec.ts.snap
new file mode 100644
index 0000000..2169512
--- /dev/null
+++ b/web-console/src/ace-modes/__snapshots__/make-doc-html.spec.ts.snap
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`makeDocHtml correctly formats helper HTML 1`] = `
+"
+<div class="doc-name">COUNT</div>
+<div class="doc-syntax">COUNT(*)</div>
+<div class="doc-description">Counts the number of things</div>"
+`;
diff --git a/web-console/src/ace-modes/dsql.js b/web-console/src/ace-modes/dsql.js
deleted file mode 100644
index f2349ee..0000000
--- a/web-console/src/ace-modes/dsql.js
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.
- */
-
-// This file a modified version of the file located at
-// https://github.com/thlorenz/brace/blob/master/mode/sql.js
-// 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-docs');
-
-ace.define(
- 'ace/mode/dsql_highlight_rules',
- ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
- function (acequire, exports, module) {
- 'use strict';
-
- var oop = acequire('../lib/oop');
- var TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
-
- var SqlHighlightRules = function () {
- // 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, '|');
-
- // Stuff like: 'true|false'
- var builtinConstants = druidKeywords.SQL_CONSTANTS.join('|');
-
- // Stuff like: 'avg|count|first|last|max|min'
- var builtinFunctions = druidKeywords.SQL_DYNAMICS.concat(
- Object.keys(druidFunctions.SQL_FUNCTIONS),
- ).join('|');
-
- // Stuff like: 'int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp'
- var dataTypes = Object.keys(druidFunctions.SQL_DATA_TYPES).join('|');
-
- var keywordMapper = this.createKeywordMapper(
- {
- 'support.function': builtinFunctions,
- 'keyword': keywords,
- 'constant.language': builtinConstants,
- 'storage.type': dataTypes,
- },
- 'identifier',
- true,
- );
-
- this.$rules = {
- start: [
- {
- token: 'comment.issue',
- regex: '--:ISSUE:.*$',
- },
- {
- token: 'comment',
- regex: '--.*$',
- },
- {
- token: 'comment',
- start: '/\\*',
- end: '\\*/',
- },
- {
- token: 'variable.column', // " quoted reference
- regex: '".*?"',
- },
- {
- token: 'string', // ' string literal
- regex: "'.*?'",
- },
- {
- token: 'constant.numeric', // float
- regex: '[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b',
- },
- {
- token: keywordMapper,
- regex: '[a-zA-Z_$][a-zA-Z0-9_$]*\\b',
- },
- {
- token: 'keyword.operator',
- regex: '\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=',
- },
- {
- token: 'paren.lparen',
- regex: '[\\(]',
- },
- {
- token: 'paren.rparen',
- regex: '[\\)]',
- },
- {
- token: 'text',
- regex: '\\s+',
- },
- ],
- };
- this.normalizeRules();
- };
-
- oop.inherits(SqlHighlightRules, TextHighlightRules);
-
- exports.SqlHighlightRules = SqlHighlightRules;
- },
-);
-
-ace.define(
- 'ace/mode/dsql',
- ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/dsql_highlight_rules'],
- function (acequire, exports, module) {
- 'use strict';
-
- var oop = acequire('../lib/oop');
- var TextMode = acequire('./text').Mode;
- var SqlHighlightRules = acequire('./dsql_highlight_rules').SqlHighlightRules;
-
- var Mode = function () {
- this.HighlightRules = SqlHighlightRules;
- this.$behaviour = this.$defaultBehaviour;
- };
- oop.inherits(Mode, TextMode);
-
- (function () {
- this.lineCommentStart = '--';
-
- this.$id = 'ace/mode/dsql';
- }).call(Mode.prototype);
-
- exports.Mode = Mode;
- },
-);
diff --git a/web-console/src/ace-modes/dsql.ts b/web-console/src/ace-modes/dsql.ts
new file mode 100644
index 0000000..e57d17d
--- /dev/null
+++ b/web-console/src/ace-modes/dsql.ts
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+// This file a modified version of the file located at
+// https://github.com/thlorenz/brace/blob/master/mode/sql.js
+// 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
+
+import type { Ace } from 'ace-builds';
+import ace from 'ace-builds/src-noconflict/ace';
+
+import * as druidKeywords from '../../lib/keywords';
+import * as druidFunctions from '../../lib/sql-docs';
+
+import type { ItemDescription } from './make-doc-html';
+import { makeDocHtml } from './make-doc-html';
+
+ace.define(
+ 'ace/mode/dsql_highlight_rules',
+ ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
+ function (acequire: any, exports: any) {
+ 'use strict';
+
+ const oop = acequire('../lib/oop');
+ const TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
+
+ const SqlHighlightRules = function (this: any) {
+ // Stuff like: 'with|select|from|where|and|or|group|by|order|limit|having|as|case|'
+ const keywords = druidKeywords.SQL_KEYWORDS.concat(druidKeywords.SQL_EXPRESSION_PARTS)
+ .join('|')
+ .replace(/\s/g, '|');
+
+ // Stuff like: 'true|false'
+ const builtinConstants = druidKeywords.SQL_CONSTANTS.join('|');
+
+ // Stuff like: 'avg|count|first|last|max|min'
+ const builtinFunctions = druidKeywords.SQL_DYNAMICS.concat(
+ Object.keys(druidFunctions.SQL_FUNCTIONS),
+ ).join('|');
+
+ // Stuff like: 'int|numeric|decimal|date|varchar|char|bigint|float|double|bit|binary|text|set|timestamp'
+ const dataTypes = Object.keys(druidFunctions.SQL_DATA_TYPES).join('|');
+
+ const keywordMapper = this.createKeywordMapper(
+ {
+ 'support.function': builtinFunctions,
+ 'keyword': keywords,
+ 'constant.language': builtinConstants,
+ 'storage.type': dataTypes,
+ },
+ 'identifier',
+ true,
+ );
+
+ this.$rules = {
+ start: [
+ {
+ token: 'comment.issue',
+ regex: '--:ISSUE:.*$',
+ },
+ {
+ token: 'comment',
+ regex: '--.*$',
+ },
+ {
+ token: 'comment',
+ start: '/\\*',
+ end: '\\*/',
+ },
+ {
+ token: 'variable.column', // " quoted reference
+ regex: '".*?"',
+ },
+ {
+ token: 'string', // ' string literal
+ regex: "'.*?'",
+ },
+ {
+ token: 'constant.numeric', // float
+ regex: '[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b',
+ },
+ {
+ token: keywordMapper,
+ regex: '[a-zA-Z_$][a-zA-Z0-9_$]*\\b',
+ },
+ {
+ token: 'keyword.operator',
+ regex: '\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=',
+ },
+ {
+ token: 'paren.lparen',
+ regex: '[\\(]',
+ },
+ {
+ token: 'paren.rparen',
+ regex: '[\\)]',
+ },
+ {
+ token: 'text',
+ regex: '\\s+',
+ },
+ ],
+ };
+ this.normalizeRules();
+ };
+
+ oop.inherits(SqlHighlightRules, TextHighlightRules);
+
+ exports.SqlHighlightRules = SqlHighlightRules;
+ },
+);
+
+ace.define(
+ 'ace/mode/dsql',
+ ['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text', 'ace/mode/dsql_highlight_rules'],
+ function (acequire: any, exports: any) {
+ 'use strict';
+
+ const oop = acequire('../lib/oop');
+ const TextMode = acequire('./text').Mode;
+ const SqlHighlightRules = acequire('./dsql_highlight_rules').SqlHighlightRules;
+
+ const completions = ([] as Ace.Completion[]).concat(
+ druidKeywords.SQL_KEYWORDS.map(v => ({ name: v, value: v, score: 0, meta: 'keyword' })),
+ druidKeywords.SQL_EXPRESSION_PARTS.map(v => ({
+ name: v,
+ value: v,
+ score: 0,
+ meta: 'keyword',
+ })),
+ druidKeywords.SQL_CONSTANTS.map(v => ({ name: v, value: v, score: 0, meta: 'constant' })),
+ druidKeywords.SQL_DYNAMICS.map(v => ({ name: v, value: v, score: 0, meta: 'dynamic' })),
+ Object.entries(druidFunctions.SQL_DATA_TYPES).map(([name, [runtime, description]]) => {
+ const item: ItemDescription = {
+ name,
+ description,
+ syntax: `Druid runtime type: ${runtime}`,
+ };
+ return {
+ name,
+ value: name,
+ score: 0,
+ meta: 'type',
+ docHTML: makeDocHtml(item),
+ docText: description,
+ };
+ }),
+ Object.entries(druidFunctions.SQL_FUNCTIONS).flatMap(([name, versions]) => {
+ return versions.map(([args, description]) => {
+ const item = { name, description, syntax: `${name}(${args})` };
+ return {
+ name,
+ value: versions.length > 1 ? `${name}(${args})` : name,
+ score: 1100, // Use a high score to appear over the 'local' suggestions that have a score of 1000
+ meta: 'function',
+ docHTML: makeDocHtml(item),
+ docText: description,
+ completer: {
+ insertMatch: (editor: any, data: any) => {
+ editor.completer.insertMatch({ value: data.name });
+ },
+ },
+ } as Ace.Completion;
+ });
+ }),
+ );
+
+ const Mode = function (this: any) {
+ this.HighlightRules = SqlHighlightRules;
+ this.$behaviour = this.$defaultBehaviour;
+ this.$id = 'ace/mode/dsql';
+
+ this.lineCommentStart = '--';
+ this.getCompletions = () => completions;
+ };
+ oop.inherits(Mode, TextMode);
+
+ exports.Mode = Mode;
+ },
+);
diff --git a/web-console/src/ace-modes/hjson.js b/web-console/src/ace-modes/hjson.ts
similarity index 89%
rename from web-console/src/ace-modes/hjson.js
rename to web-console/src/ace-modes/hjson.ts
index 316ce98..1c58a5c 100644
--- a/web-console/src/ace-modes/hjson.js
+++ b/web-console/src/ace-modes/hjson.ts
@@ -22,16 +22,18 @@
// This file was modified to remove the folding functionality that did not play nice when loaded along side the
// sql mode (which does not have any folding function)
+import ace from 'ace-builds/src-noconflict/ace';
+
ace.define(
'ace/mode/hjson_highlight_rules',
['require', 'exports', 'module', 'ace/lib/oop', 'ace/mode/text_highlight_rules'],
- function (acequire, exports, module) {
+ function (acequire: any, exports: any) {
'use strict';
- var oop = acequire('../lib/oop');
- var TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
+ const oop = acequire('../lib/oop');
+ const TextHighlightRules = acequire('./text_highlight_rules').TextHighlightRules;
- var HjsonHighlightRules = function () {
+ const HjsonHighlightRules = function (this: any) {
this.$rules = {
'start': [
{
@@ -107,7 +109,7 @@
'#keyname': [
{
token: 'keyword',
- regex: /(?:[^,\{\[\}\]\s]+|"(?:[^"\\]|\\.)*")\s*(?=:)/,
+ regex: /(?:[^,{[}\]\s]+|"(?:[^"\\]|\\.)*")\s*(?=:)/,
},
],
'#mstring': [
@@ -166,7 +168,7 @@
'#rootObject': [
{
token: 'paren',
- regex: /(?=\s*(?:[^,\{\[\}\]\s]+|"(?:[^"\\]|\\.)*")\s*:)/,
+ regex: /(?=\s*(?:[^,{[}\]\s]+|"(?:[^"\\]|\\.)*")\s*:)/,
push: [
{
token: 'paren.rparen',
@@ -205,7 +207,7 @@
},
{
token: 'constant.language.escape',
- regex: /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/,
+ regex: /\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/,
},
{
token: 'invalid.illegal',
@@ -220,7 +222,7 @@
'#ustring': [
{
token: 'string',
- regex: /\b[^:,0-9\-\{\[\}\]\s].*$/,
+ regex: /\b[^:,0-9\-{[}\]\s].*$/,
},
],
'#value': [
@@ -277,19 +279,19 @@
'ace/mode/text',
'ace/mode/hjson_highlight_rules',
],
- function (acequire, exports, module) {
+ function (acequire: any, exports: any) {
'use strict';
- var oop = acequire('../lib/oop');
- var TextMode = acequire('./text').Mode;
- var HjsonHighlightRules = acequire('./hjson_highlight_rules').HjsonHighlightRules;
+ const oop = acequire('../lib/oop');
+ const TextMode = acequire('./text').Mode;
+ const HjsonHighlightRules = acequire('./hjson_highlight_rules').HjsonHighlightRules;
- var Mode = function () {
+ const Mode = function (this: any) {
this.HighlightRules = HjsonHighlightRules;
};
oop.inherits(Mode, TextMode);
- (function () {
+ (function (this: any) {
this.lineCommentStart = '//';
this.blockComment = { start: '/*', end: '*/' };
this.$id = 'ace/mode/hjson';
diff --git a/web-console/src/ace-modes/make-doc-html.spec.ts b/web-console/src/ace-modes/make-doc-html.spec.ts
new file mode 100644
index 0000000..35172d0
--- /dev/null
+++ b/web-console/src/ace-modes/make-doc-html.spec.ts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+import { makeDocHtml } from './make-doc-html';
+
+describe('makeDocHtml', () => {
+ it('correctly formats helper HTML', () => {
+ expect(
+ makeDocHtml({
+ name: 'COUNT',
+ syntax: 'COUNT(*)',
+ description: 'Counts the number of things',
+ }),
+ ).toMatchSnapshot();
+ });
+});
diff --git a/web-console/src/ace-modes/make-doc-html.ts b/web-console/src/ace-modes/make-doc-html.ts
new file mode 100644
index 0000000..996541b
--- /dev/null
+++ b/web-console/src/ace-modes/make-doc-html.ts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+import escape from 'lodash.escape';
+
+export interface ItemDescription {
+ name: string;
+ syntax: string;
+ description: string;
+}
+
+export function makeDocHtml(item: ItemDescription) {
+ return `
+<div class="doc-name">${item.name}</div>
+<div class="doc-syntax">${escape(item.syntax)}</div>
+<div class="doc-description">${item.description}</div>`;
+}
diff --git a/web-console/src/components/json-input/__snapshots__/json-input.spec.tsx.snap b/web-console/src/components/json-input/__snapshots__/json-input.spec.tsx.snap
index e96b7f6..b71b692 100644
--- a/web-console/src/components/json-input/__snapshots__/json-input.spec.tsx.snap
+++ b/web-console/src/components/json-input/__snapshots__/json-input.spec.tsx.snap
@@ -5,7 +5,7 @@
class="json-input"
>
<div
- class=" ace_editor ace_hidpi ace-tm"
+ class=" ace_editor ace_hidpi ace-solarized-dark ace_dark"
id="ace-editor"
style="width: 100%; height: 8vh; font-size: 12px;"
>
@@ -104,7 +104,7 @@
class="json-input"
>
<div
- class=" ace_editor ace_hidpi ace-tm"
+ class=" ace_editor ace_hidpi ace-solarized-dark ace_dark"
id="ace-editor"
style="width: 100%; height: 8vh; font-size: 12px;"
>
diff --git a/web-console/src/dialogs/spec-dialog/__snapshots__/spec-dialog.spec.tsx.snap b/web-console/src/dialogs/spec-dialog/__snapshots__/spec-dialog.spec.tsx.snap
index cc8b602..cc09716 100644
--- a/web-console/src/dialogs/spec-dialog/__snapshots__/spec-dialog.spec.tsx.snap
+++ b/web-console/src/dialogs/spec-dialog/__snapshots__/spec-dialog.spec.tsx.snap
@@ -58,7 +58,7 @@
</button>
</div>
<div
- class=" ace_editor ace_hidpi ace-tm spec-dialog-textarea placeholder-padding"
+ class=" ace_editor ace_hidpi ace-solarized-dark ace_dark spec-dialog-textarea placeholder-padding"
id="ace-editor"
style="width: 100%; height: 500px; font-size: 12px;"
>
@@ -252,7 +252,7 @@
</button>
</div>
<div
- class=" ace_editor ace_hidpi ace-tm spec-dialog-textarea placeholder-padding"
+ class=" ace_editor ace_hidpi ace-solarized-dark ace_dark spec-dialog-textarea placeholder-padding"
id="ace-editor"
style="width: 100%; height: 500px; font-size: 12px;"
>
diff --git a/web-console/src/setup-tests.ts b/web-console/src/setup-tests.ts
index e75cb3b..518045d 100644
--- a/web-console/src/setup-tests.ts
+++ b/web-console/src/setup-tests.ts
@@ -17,6 +17,7 @@
*/
import 'core-js/stable';
+import './bootstrap/ace';
import { UrlBaser } from './singletons';
diff --git a/web-console/src/views/workbench-view/explain-dialog/__snapshots__/explain-dialog.spec.tsx.snap b/web-console/src/views/workbench-view/explain-dialog/__snapshots__/explain-dialog.spec.tsx.snap
index bbbca4b..c0332ad 100644
--- a/web-console/src/views/workbench-view/explain-dialog/__snapshots__/explain-dialog.spec.tsx.snap
+++ b/web-console/src/views/workbench-view/explain-dialog/__snapshots__/explain-dialog.spec.tsx.snap
@@ -122,7 +122,7 @@
enableLiveAutocompletion={false}
enableSnippets={false}
focus={false}
- fontSize={13}
+ fontSize={12}
height="100%"
highlightActiveLine={true}
maxLines={null}
@@ -220,7 +220,7 @@
enableLiveAutocompletion={false}
enableSnippets={false}
focus={false}
- fontSize={13}
+ fontSize={12}
height="100%"
highlightActiveLine={true}
maxLines={null}
@@ -348,7 +348,7 @@
enableLiveAutocompletion={false}
enableSnippets={false}
focus={false}
- fontSize={13}
+ fontSize={12}
height="100%"
highlightActiveLine={true}
maxLines={null}
diff --git a/web-console/src/views/workbench-view/explain-dialog/explain-dialog.tsx b/web-console/src/views/workbench-view/explain-dialog/explain-dialog.tsx
index 3c535ed..4bab7e7 100644
--- a/web-console/src/views/workbench-view/explain-dialog/explain-dialog.tsx
+++ b/web-console/src/views/workbench-view/explain-dialog/explain-dialog.tsx
@@ -131,7 +131,7 @@
theme="solarized_dark"
className="query-string"
name="ace-editor"
- fontSize={13}
+ fontSize={12}
width="100%"
height="100%"
showGutter
diff --git a/web-console/src/views/workbench-view/flexible-query-input/__snapshots__/flexible-query-input.spec.tsx.snap b/web-console/src/views/workbench-view/flexible-query-input/__snapshots__/flexible-query-input.spec.tsx.snap
index 0efa8f7..902b465 100644
--- a/web-console/src/views/workbench-view/flexible-query-input/__snapshots__/flexible-query-input.spec.tsx.snap
+++ b/web-console/src/views/workbench-view/flexible-query-input/__snapshots__/flexible-query-input.spec.tsx.snap
@@ -1,12 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`FlexibleQueryInput correctly formats helper HTML 1`] = `
-"
-<div class="doc-name">COUNT</div>
-<div class="doc-syntax">COUNT(*)</div>
-<div class="doc-description">Counts the number of things</div>"
-`;
-
exports[`FlexibleQueryInput matches snapshot 1`] = `
<div
class="flexible-query-input"
@@ -15,9 +8,9 @@
class="ace-container query-idle"
>
<div
- class=" ace_editor ace_hidpi ace-tm placeholder-padding no-background ace_focus"
+ class=" ace_editor ace_hidpi ace-solarized-dark ace_dark placeholder-padding no-background ace_focus"
id="ace-editor"
- style="width: 100%; height: 200px; font-size: 13px;"
+ style="width: 100%; height: 200px; font-size: 12px;"
>
<textarea
autocapitalize="off"
diff --git a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.spec.tsx b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.spec.tsx
index 9a2b5b2..06b7124 100644
--- a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.spec.tsx
+++ b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.spec.tsx
@@ -30,14 +30,4 @@
const { container } = render(sqlControl);
expect(container.firstChild).toMatchSnapshot();
});
-
- it('correctly formats helper HTML', () => {
- expect(
- FlexibleQueryInput.makeDocHtml({
- name: 'COUNT',
- syntax: 'COUNT(*)',
- description: 'Counts the number of things',
- }),
- ).toMatchSnapshot();
- });
});
diff --git a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx
index e9eb368..2417b64 100644
--- a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx
+++ b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx
@@ -24,17 +24,9 @@
import ace from 'ace-builds';
import classNames from 'classnames';
import debounce from 'lodash.debounce';
-import escape from 'lodash.escape';
import React from 'react';
import AceEditor from 'react-ace';
-import {
- SQL_CONSTANTS,
- SQL_DYNAMICS,
- SQL_EXPRESSION_PARTS,
- SQL_KEYWORDS,
-} from '../../../../lib/keywords';
-import { SQL_DATA_TYPES, SQL_FUNCTIONS } from '../../../../lib/sql-docs';
import { AppToaster } from '../../../singletons';
import { AceEditorStateCache } from '../../../singletons/ace-editor-state-cache';
import type { ColumnMetadata, QuerySlice, RowColumn } from '../../../utils';
@@ -46,18 +38,6 @@
const V_PADDING = 10;
-const COMPLETER = {
- insertMatch: (editor: any, data: Ace.Completion) => {
- editor.completer.insertMatch({ value: data.name });
- },
-};
-
-interface ItemDescription {
- name: string;
- syntax: string;
- description: string;
-}
-
export interface FlexibleQueryInputProps {
queryString: string;
onQueryStringChange?: (newQueryString: string) => void;
@@ -87,85 +67,29 @@
FlexibleQueryInputProps,
FlexibleQueryInputState
> {
+ static aceTheme = 'solarized_dark';
+
private aceEditor: Ace.Editor | undefined;
private lastFoundQueries: QuerySlice[] = [];
private highlightFoundQuery: { row: number; marker: number } | undefined;
- static replaceDefaultAutoCompleter(): void {
- if (!langTools) return;
-
- const keywordList = ([] as Ace.Completion[]).concat(
- SQL_KEYWORDS.map(v => ({ name: v, value: v, score: 0, meta: 'keyword' })),
- SQL_EXPRESSION_PARTS.map(v => ({ name: v, value: v, score: 0, meta: 'keyword' })),
- SQL_CONSTANTS.map(v => ({ name: v, value: v, score: 0, meta: 'constant' })),
- SQL_DYNAMICS.map(v => ({ name: v, value: v, score: 0, meta: 'dynamic' })),
- Object.entries(SQL_DATA_TYPES).map(([name, [runtime, description]]) => ({
- name,
- value: name,
- score: 0,
- meta: 'type',
- syntax: `Druid runtime type: ${runtime}`,
- description,
- })),
- );
-
- langTools.setCompleters([
- langTools.snippetCompleter,
- langTools.textCompleter,
- {
- getCompletions: (
- _state: string,
- _session: Ace.EditSession,
- _pos: Ace.Point,
- _prefix: string,
- callback: any,
- ) => {
- return callback(null, keywordList);
- },
- getDocTooltip: (item: any) => {
- if (item.meta === 'type') {
- item.docHTML = FlexibleQueryInput.makeDocHtml(item);
- }
- },
+ private readonly aceCompleters: Ace.Completer[] = [
+ // Prepend with default completers to ensure completion data from
+ // editing mode (e.g. 'dsql') is included in addition to local completions
+ langTools.snippetCompleter,
+ langTools.keyWordCompleter,
+ langTools.textCompleter,
+ // Local completions
+ {
+ getCompletions: (_state, session, pos, prefix, callback) => {
+ const charBeforePrefix = session.getLine(pos.row)[pos.column - prefix.length - 1];
+ callback(
+ null,
+ charBeforePrefix === '"' ? this.state.unquotedCompletions : this.state.quotedCompletions,
+ );
},
- ]);
- }
-
- static addFunctionAutoCompleter(): void {
- if (!langTools) return;
-
- const functionList: Ace.Completion[] = Object.entries(SQL_FUNCTIONS).flatMap(
- ([name, versions]) => {
- return versions.map(([args, description]) => ({
- name: name,
- value: versions.length > 1 ? `${name}(${args})` : name,
- score: 1100, // Use a high score to appear over the 'local' suggestions that have a score of 1000
- meta: 'function',
- syntax: `${name}(${args})`,
- description,
- completer: COMPLETER,
- }));
- },
- );
-
- langTools.addCompleter({
- getCompletions: (_editor: any, _session: any, _pos: any, _prefix: any, callback: any) => {
- callback(null, functionList);
- },
- getDocTooltip: (item: any) => {
- if (item.meta === 'function') {
- item.docHTML = FlexibleQueryInput.makeDocHtml(item);
- }
- },
- });
- }
-
- static makeDocHtml(item: ItemDescription) {
- return `
-<div class="doc-name">${item.name}</div>
-<div class="doc-syntax">${escape(item.syntax)}</div>
-<div class="doc-description">${item.description}</div>`;
- }
+ },
+ ];
static getCompletions(
columnMetadata: readonly ColumnMetadata[],
@@ -186,7 +110,7 @@
).map(v => ({
value: quote ? String(T(v)) : v,
score: 49,
- meta: 'datasource',
+ meta: 'table',
})),
uniq(
columnMetadata
@@ -244,28 +168,6 @@
}
componentDidMount(): void {
- FlexibleQueryInput.replaceDefaultAutoCompleter();
- FlexibleQueryInput.addFunctionAutoCompleter();
- if (langTools) {
- langTools.addCompleter({
- getCompletions: (
- _state: string,
- session: Ace.EditSession,
- pos: Ace.Point,
- prefix: string,
- callback: any,
- ) => {
- const charBeforePrefix = session.getLine(pos.row)[pos.column - prefix.length - 1];
- callback(
- null,
- charBeforePrefix === '"'
- ? this.state.unquotedCompletions
- : this.state.quotedCompletions,
- );
- },
- });
- }
-
this.markQueries();
}
@@ -345,32 +247,32 @@
return (
<AceEditor
mode={jsonMode ? 'hjson' : 'dsql'}
- theme="solarized_dark"
+ theme={FlexibleQueryInput.aceTheme}
className={classNames(
'placeholder-padding',
this.props.leaveBackground ? undefined : 'no-background',
)}
+ // 'react-ace' types are incomplete. Completion options can accept completers array.
+ enableBasicAutocompletion={jsonMode ? true : (this.aceCompleters as any)}
+ enableLiveAutocompletion={jsonMode ? true : (this.aceCompleters as any)}
name="ace-editor"
onChange={this.handleChange}
focus
- fontSize={13}
+ fontSize={12}
width="100%"
height={editorHeight + 'px'}
showGutter={showGutter}
showPrintMargin={false}
+ tabSize={2}
value={queryString}
readOnly={!onQueryStringChange}
editorProps={{
$blockScrolling: Infinity,
}}
setOptions={{
- enableBasicAutocompletion: !jsonMode,
- enableLiveAutocompletion: !jsonMode,
showLineNumbers: true,
- tabSize: 2,
newLineMode: 'unix' as any, // This type is specified incorrectly in AceEditor
}}
- style={{}}
placeholder={placeholder || 'SELECT * FROM ...'}
onLoad={(editor: Ace.Editor) => {
editor.renderer.setPadding(V_PADDING);
diff --git a/web-console/src/views/workbench-view/workbench-history-dialog/workbench-history-dialog.tsx b/web-console/src/views/workbench-view/workbench-history-dialog/workbench-history-dialog.tsx
index e5d83cc..2d85a18 100644
--- a/web-console/src/views/workbench-view/workbench-history-dialog/workbench-history-dialog.tsx
+++ b/web-console/src/views/workbench-view/workbench-history-dialog/workbench-history-dialog.tsx
@@ -78,7 +78,7 @@
theme="solarized_dark"
className="query-string"
name="ace-editor"
- fontSize={13}
+ fontSize={12}
width="100%"
showGutter
showPrintMargin={false}