From 687f20550891769062e856a7e4d81db6a5dfde47 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Sat, 1 Jun 2019 09:02:42 -0700 Subject: [PATCH] Wrapping up #7130 (#7633) * [SQL Lab] Adds autocomplete on table names and auto-add to schema browser Closes #7059 * Wrapping up #7130 For more details see #7130, this PR addresses the merge conflicts. --- superset/assets/src/SqlLab/actions/sqlLab.js | 10 +++++++ .../SqlLab/components/AceEditorWrapper.jsx | 28 ++++++++++++++++--- .../src/SqlLab/components/SqlEditor.jsx | 4 ++- .../SqlLab/components/SqlEditorLeftBar.jsx | 10 +++++++ superset/assets/src/SqlLab/reducers/sqlLab.js | 6 ++++ .../assets/src/components/TableSelector.jsx | 6 ++++ 6 files changed, 59 insertions(+), 5 deletions(-) diff --git a/superset/assets/src/SqlLab/actions/sqlLab.js b/superset/assets/src/SqlLab/actions/sqlLab.js index 9c5a9d04826..8172c495cb4 100644 --- a/superset/assets/src/SqlLab/actions/sqlLab.js +++ b/superset/assets/src/SqlLab/actions/sqlLab.js @@ -42,6 +42,8 @@ export const EXPAND_TABLE = 'EXPAND_TABLE'; export const COLLAPSE_TABLE = 'COLLAPSE_TABLE'; export const QUERY_EDITOR_SETDB = 'QUERY_EDITOR_SETDB'; export const QUERY_EDITOR_SET_SCHEMA = 'QUERY_EDITOR_SET_SCHEMA'; +export const QUERY_EDITOR_SET_SCHEMA_OPTIONS = 'QUERY_EDITOR_SET_SCHEMA_OPTIONS'; +export const QUERY_EDITOR_SET_TABLE_OPTIONS = 'QUERY_EDITOR_SET_TABLE_OPTIONS'; export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE'; export const QUERY_EDITOR_SET_AUTORUN = 'QUERY_EDITOR_SET_AUTORUN'; export const QUERY_EDITOR_SET_SQL = 'QUERY_EDITOR_SET_SQL'; @@ -305,6 +307,14 @@ export function queryEditorSetSchema(queryEditor, schema) { return { type: QUERY_EDITOR_SET_SCHEMA, queryEditor, schema }; } +export function queryEditorSetSchemaOptions(queryEditor, options) { + return { type: QUERY_EDITOR_SET_SCHEMA_OPTIONS, queryEditor, options }; +} + +export function queryEditorSetTableOptions(queryEditor, options) { + return { type: QUERY_EDITOR_SET_TABLE_OPTIONS, queryEditor, options }; +} + export function queryEditorSetAutorun(queryEditor, autorun) { return { type: QUERY_EDITOR_SET_AUTORUN, queryEditor, autorun }; } diff --git a/superset/assets/src/SqlLab/components/AceEditorWrapper.jsx b/superset/assets/src/SqlLab/components/AceEditorWrapper.jsx index 6c87ec27c56..7815998fe73 100644 --- a/superset/assets/src/SqlLab/components/AceEditorWrapper.jsx +++ b/superset/assets/src/SqlLab/components/AceEditorWrapper.jsx @@ -48,7 +48,9 @@ const propTypes = { actions: PropTypes.object.isRequired, onBlur: PropTypes.func, sql: PropTypes.string.isRequired, + schemas: PropTypes.array, tables: PropTypes.array, + extendedTables: PropTypes.array, queryEditor: PropTypes.object.isRequired, height: PropTypes.string, hotkeys: PropTypes.arrayOf(PropTypes.shape({ @@ -62,7 +64,9 @@ const propTypes = { const defaultProps = { onBlur: () => {}, onChange: () => {}, + schemas: [], tables: [], + extendedTables: [], }; class AceEditorWrapper extends React.PureComponent { @@ -80,7 +84,9 @@ class AceEditorWrapper extends React.PureComponent { this.setAutoCompleter(this.props); } componentWillReceiveProps(nextProps) { - if (!areArraysShallowEqual(this.props.tables, nextProps.tables)) { + if (!areArraysShallowEqual(this.props.tables, nextProps.tables) || + !areArraysShallowEqual(this.props.schemas, nextProps.schemas) || + !areArraysShallowEqual(this.props.extendedTables, nextProps.extendedTables)) { this.setAutoCompleter(nextProps); } if (nextProps.sql !== this.props.sql) { @@ -126,6 +132,13 @@ class AceEditorWrapper extends React.PureComponent { getCompletions(aceEditor, session, pos, prefix, callback) { const completer = { insertMatch: (editor, data) => { + if (data.meta === 'table') { + this.props.actions.addTable( + this.props.queryEditor, + data.value, + this.props.queryEditor.schema, + ); + } editor.completer.insertMatch({ value: data.caption + ' ' }); }, }; @@ -133,13 +146,20 @@ class AceEditorWrapper extends React.PureComponent { callback(null, words); } setAutoCompleter(props) { - // Loading table and column names as auto-completable words + // Loading schema, table and column names as auto-completable words let words = []; + const schemas = props.schemas || []; + schemas.forEach((s) => { + words.push({ name: s.label, value: s.value, score: 60, meta: 'schema' }); + }); const columns = {}; const tables = props.tables || []; + const extendedTables = props.extendedTables || []; tables.forEach((t) => { - words.push({ name: t.name, value: t.name, score: 55, meta: 'table' }); - const cols = t.columns || []; + const tableName = t.value.table; + words.push({ name: t.label, value: tableName, score: 55, meta: 'table' }); + const extendedTable = extendedTables.find(et => et.name === tableName); + const cols = extendedTable && extendedTable.columns || []; cols.forEach((col) => { columns[col.name] = null; // using an object as a unique set }); diff --git a/superset/assets/src/SqlLab/components/SqlEditor.jsx b/superset/assets/src/SqlLab/components/SqlEditor.jsx index 87930d93644..5d58b2330b8 100644 --- a/superset/assets/src/SqlLab/components/SqlEditor.jsx +++ b/superset/assets/src/SqlLab/components/SqlEditor.jsx @@ -298,7 +298,9 @@ class SqlEditor extends React.PureComponent { onChange={this.onSqlChanged} queryEditor={this.props.queryEditor} sql={this.props.queryEditor.sql} - tables={this.props.tables} + schemas={this.props.queryEditor.schemaOptions} + tables={this.props.queryEditor.tableOptions} + extendedTables={this.props.tables} height={`${aceEditorHeight}px`} hotkeys={hotkeys} /> diff --git a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx index f3896411174..bc61f83de73 100644 --- a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx +++ b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx @@ -50,6 +50,8 @@ export default class SqlEditorLeftBar extends React.PureComponent { }; this.resetState = this.resetState.bind(this); this.onSchemaChange = this.onSchemaChange.bind(this); + this.onSchemasLoad = this.onSchemasLoad.bind(this); + this.onTablesLoad = this.onTablesLoad.bind(this); this.onDbChange = this.onDbChange.bind(this); this.getDbList = this.getDbList.bind(this); this.onTableChange = this.onTableChange.bind(this); @@ -57,6 +59,12 @@ export default class SqlEditorLeftBar extends React.PureComponent { onSchemaChange(schema) { this.props.actions.queryEditorSetSchema(this.props.queryEditor, schema); } + onSchemasLoad(schemas) { + this.props.actions.queryEditorSetSchemaOptions(this.props.queryEditor, schemas); + } + onTablesLoad(tables) { + this.props.actions.queryEditorSetTableOptions(this.props.queryEditor, tables); + } onDbChange(db) { this.props.actions.queryEditorSetDb(this.props.queryEditor, db.id); } @@ -105,6 +113,8 @@ export default class SqlEditorLeftBar extends React.PureComponent { schema={qe.schema} onDbChange={this.onDbChange} onSchemaChange={this.onSchemaChange} + onSchemasLoad={this.onSchemasLoad} + onTablesLoad={this.onTablesLoad} getDbList={this.getDbList} onTableChange={this.onTableChange} tableNameSticky={false} diff --git a/superset/assets/src/SqlLab/reducers/sqlLab.js b/superset/assets/src/SqlLab/reducers/sqlLab.js index 7a21e829d43..2244096d471 100644 --- a/superset/assets/src/SqlLab/reducers/sqlLab.js +++ b/superset/assets/src/SqlLab/reducers/sqlLab.js @@ -283,6 +283,12 @@ export default function sqlLabReducer(state = {}, action) { [actions.QUERY_EDITOR_SET_SCHEMA]() { return alterInArr(state, 'queryEditors', action.queryEditor, { schema: action.schema }); }, + [actions.QUERY_EDITOR_SET_SCHEMA_OPTIONS]() { + return alterInArr(state, 'queryEditors', action.queryEditor, { schemaOptions: action.options }); + }, + [actions.QUERY_EDITOR_SET_TABLE_OPTIONS]() { + return alterInArr(state, 'queryEditors', action.queryEditor, { tableOptions: action.options }); + }, [actions.QUERY_EDITOR_SET_TITLE]() { return alterInArr(state, 'queryEditors', action.queryEditor, { title: action.title }); }, diff --git a/superset/assets/src/components/TableSelector.jsx b/superset/assets/src/components/TableSelector.jsx index 940e1c274b9..6d232d49405 100644 --- a/superset/assets/src/components/TableSelector.jsx +++ b/superset/assets/src/components/TableSelector.jsx @@ -33,6 +33,8 @@ const propTypes = { schema: PropTypes.string, onSchemaChange: PropTypes.func, onDbChange: PropTypes.func, + onSchemasLoad: PropTypes.func, + onTablesLoad: PropTypes.func, getDbList: PropTypes.func, onTableChange: PropTypes.func, tableNameSticky: PropTypes.bool, @@ -47,6 +49,8 @@ const propTypes = { const defaultProps = { onDbChange: () => {}, onSchemaChange: () => {}, + onSchemasLoad: () => {}, + onTablesLoad: () => {}, getDbList: () => {}, onTableChange: () => {}, onChange: () => {}, @@ -136,6 +140,7 @@ export default class TableSelector extends React.PureComponent { title: o.label, })), })); + this.props.onTablesLoad(json.options); }) .catch(() => { this.setState(() => ({ tableLoading: false, tableOptions: [] })); @@ -156,6 +161,7 @@ export default class TableSelector extends React.PureComponent { .then(({ json }) => { const schemaOptions = json.schemas.map(s => ({ value: s, label: s, title: s })); this.setState({ schemaOptions, schemaLoading: false }); + this.props.onSchemasLoad(schemaOptions); }) .catch(() => { this.setState({ schemaLoading: false, schemaOptions: [] });