diff --git a/superset-frontend/spec/javascripts/sqllab/SqlEditor_spec.jsx b/superset-frontend/spec/javascripts/sqllab/SqlEditor_spec.jsx index cb1002f5de973..a97cebdbab684 100644 --- a/superset-frontend/spec/javascripts/sqllab/SqlEditor_spec.jsx +++ b/superset-frontend/spec/javascripts/sqllab/SqlEditor_spec.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; import { shallow } from 'enzyme'; +import { Checkbox } from 'react-bootstrap'; import { defaultQueryEditor, initialState, queries, table } from './fixtures'; import { @@ -105,4 +106,13 @@ describe('SqlEditor', () => { queryEditor.queryLimit, ); }); + it('allows toggling autocomplete', () => { + const wrapper = shallow(); + expect(wrapper.find(AceEditorWrapper).props().autocomplete).toBe(true); + wrapper + .find(Checkbox) + .props() + .onChange(); + expect(wrapper.find(AceEditorWrapper).props().autocomplete).toBe(false); + }); }); diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper.jsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx similarity index 82% rename from superset-frontend/src/SqlLab/components/AceEditorWrapper.jsx rename to superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx index aa31827d66844..370cdbcb910c9 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper.jsx +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper.tsx @@ -17,7 +17,6 @@ * under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import AceEditor from 'react-ace'; import 'brace/mode/sql'; import 'brace/theme/github'; @@ -34,41 +33,53 @@ import { const langTools = ace.acequire('ace/ext/language_tools'); -const propTypes = { - actions: PropTypes.object.isRequired, - onBlur: PropTypes.func, - sql: PropTypes.string.isRequired, - schemas: PropTypes.array, - tables: PropTypes.array, - functionNames: PropTypes.array, - extendedTables: PropTypes.array, - queryEditor: PropTypes.object.isRequired, - height: PropTypes.string, - hotkeys: PropTypes.arrayOf( - PropTypes.shape({ - key: PropTypes.string.isRequired, - descr: PropTypes.string.isRequired, - func: PropTypes.func.isRequired, - }), - ), - onChange: PropTypes.func, +type HotKey = { + key: string; + descr: string; + name: string; + func: () => void; }; -const defaultProps = { - onBlur: () => {}, - onChange: () => {}, - schemas: [], - tables: [], - functionNames: [], - extendedTables: [], -}; +interface Props { + actions: { + queryEditorSetSelectedText: (edit: any, text: null | string) => void; + addTable: (queryEditor: any, value: any, schema: any) => void; + }; + autocomplete: boolean; + onBlur: (sql: string) => void; + sql: string; + schemas: any[]; + tables: any[]; + functionNames: string[]; + extendedTables: Array<{ name: string; columns: any[] }>; + queryEditor: any; + height: string; + hotkeys: HotKey[]; + onChange: (sql: string) => void; +} + +interface State { + sql: string; + selectedText: string; + words: any[]; +} + +class AceEditorWrapper extends React.PureComponent { + static defaultProps = { + onBlur: () => {}, + onChange: () => {}, + schemas: [], + tables: [], + functionNames: [], + extendedTables: [], + }; -class AceEditorWrapper extends React.PureComponent { - constructor(props) { + constructor(props: Props) { super(props); this.state = { sql: props.sql, selectedText: '', + words: [], }; this.onChange = this.onChange.bind(this); } @@ -77,7 +88,7 @@ class AceEditorWrapper extends React.PureComponent { this.props.actions.queryEditorSetSelectedText(this.props.queryEditor, null); this.setAutoCompleter(this.props); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if ( !areArraysShallowEqual(this.props.tables, nextProps.tables) || !areArraysShallowEqual(this.props.schemas, nextProps.schemas) || @@ -98,7 +109,7 @@ class AceEditorWrapper extends React.PureComponent { onAltEnter() { this.props.onBlur(this.state.sql); } - onEditorLoad(editor) { + onEditorLoad(editor: any) { editor.commands.addCommand({ name: 'runQuery', bindKey: { win: 'Alt-enter', mac: 'Alt-enter' }, @@ -129,18 +140,24 @@ class AceEditorWrapper extends React.PureComponent { } }); } - onChange(text) { + onChange(text: string) { this.setState({ sql: text }); this.props.onChange(text); } - getCompletions(aceEditor, session, pos, prefix, callback) { + getCompletions( + aceEditor: any, + session: any, + pos: any, + prefix: string, + callback: (p0: any, p1: any[]) => void, + ) { // If the prefix starts with a number, don't try to autocomplete with a // table name or schema or anything else if (!isNaN(parseInt(prefix, 10))) { return; } const completer = { - insertMatch: (editor, data) => { + insertMatch: (editor: any, data: any) => { if (data.meta === 'table') { this.props.actions.addTable( this.props.queryEditor, @@ -163,7 +180,7 @@ class AceEditorWrapper extends React.PureComponent { }); callback(null, words); } - setAutoCompleter(props) { + setAutoCompleter(props: Props) { // Loading schema, table and column names as auto-completable words const schemas = props.schemas || []; const schemaWords = schemas.map(s => ({ @@ -223,7 +240,7 @@ class AceEditorWrapper extends React.PureComponent { const validationResult = this.props.queryEditor.validationResult; const resultIsReady = validationResult && validationResult.completed; if (resultIsReady && validationResult.errors.length > 0) { - const errors = validationResult.errors.map(err => ({ + const errors = validationResult.errors.map((err: any) => ({ type: 'error', row: err.line_number - 1, column: err.start_column - 1, @@ -244,14 +261,12 @@ class AceEditorWrapper extends React.PureComponent { onChange={this.onChange} width="100%" editorProps={{ $blockScrolling: true }} - enableLiveAutocompletion + enableLiveAutocompletion={this.props.autocomplete} value={this.state.sql} annotations={this.getAceAnnotations()} /> ); } } -AceEditorWrapper.defaultProps = defaultProps; -AceEditorWrapper.propTypes = propTypes; export default AceEditorWrapper; diff --git a/superset-frontend/src/SqlLab/components/SqlEditor.jsx b/superset-frontend/src/SqlLab/components/SqlEditor.jsx index 138093f9f6c06..11edbf7c4d81e 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor.jsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor.jsx @@ -20,6 +20,7 @@ import React from 'react'; import { CSSTransition } from 'react-transition-group'; import PropTypes from 'prop-types'; import { + Checkbox, FormGroup, InputGroup, Form, @@ -93,6 +94,7 @@ class SqlEditor extends React.PureComponent { northPercent: props.queryEditor.northPercent || INITIAL_NORTH_PERCENT, southPercent: props.queryEditor.southPercent || INITIAL_SOUTH_PERCENT, sql: props.queryEditor.sql, + autocompleteEnabled: true, }; this.sqlEditorRef = React.createRef(); this.northPaneRef = React.createRef(); @@ -245,6 +247,9 @@ class SqlEditor extends React.PureComponent { handleWindowResize() { this.setState({ height: this.getSqlEditorHeight() }); } + handleToggleAutocompleteEnabled = () => { + this.setState({ autocompleteEnabled: !this.state.autocompleteEnabled }); + }; elementStyle(dimension, elementSize, gutterSize) { return { [dimension]: `calc(${elementSize}% - ${gutterSize + @@ -337,6 +342,7 @@ class SqlEditor extends React.PureComponent {
+ + + {t('Autocomplete')} + + {