diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js b/superset-frontend/src/SqlLab/actions/sqlLab.js index edb9f3462d4..91b4495dd98 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.js @@ -952,7 +952,7 @@ export function addTable(queryEditor, tableName, catalogName, schemaName) { const { dbId } = getUpToDateQuery(getState(), queryEditor, queryEditor.id); const table = { dbId, - queryEditorId: queryEditor.id, + queryEditorId: queryEditor.tabViewId ?? queryEditor.id, catalog: catalogName, schema: schemaName, name: tableName, diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.test.js b/superset-frontend/src/SqlLab/actions/sqlLab.test.js index 0280a283a66..aa1ddfb1cde 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.test.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.test.js @@ -1002,6 +1002,85 @@ describe('async actions', () => { }), ); }); + + it('uses tabViewId when available', () => { + const tableName = 'table'; + const catalogName = null; + const schemaName = 'schema'; + const expectedDbId = 473892; + const tabViewId = '123'; + const queryWithTabViewId = { ...query, tabViewId }; + + const store = mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: query.id, + dbId: expectedDbId, + }, + }, + }); + + const request = actions.addTable( + queryWithTabViewId, + tableName, + catalogName, + schemaName, + ); + request(store.dispatch, store.getState); + + expect(store.getActions()[0]).toEqual( + expect.objectContaining({ + table: expect.objectContaining({ + name: tableName, + catalog: catalogName, + schema: schemaName, + dbId: expectedDbId, + queryEditorId: tabViewId, // Should use tabViewId, not id + }), + }), + ); + }); + + it('falls back to id when tabViewId is not available', () => { + const tableName = 'table'; + const catalogName = null; + const schemaName = 'schema'; + const expectedDbId = 473892; + const queryWithoutTabViewId = { ...query, tabViewId: undefined }; + + const store = mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: query.id, + dbId: expectedDbId, + }, + }, + }); + + const request = actions.addTable( + queryWithoutTabViewId, + tableName, + catalogName, + schemaName, + ); + request(store.dispatch, store.getState); + + expect(store.getActions()[0]).toEqual( + expect.objectContaining({ + table: expect.objectContaining({ + name: tableName, + catalog: catalogName, + schema: schemaName, + dbId: expectedDbId, + queryEditorId: query.id, // Should use id when tabViewId is not available + }), + }), + ); + }); }); describe('syncTable', () => { diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx index bfa615765b6..23931a593ea 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/index.tsx @@ -65,6 +65,7 @@ const AceEditorWrapper = ({ 'catalog', 'schema', 'templateParams', + 'tabViewId', ]); // Prevent a maximum update depth exceeded error // by skipping access the unsaved query editor state @@ -172,6 +173,7 @@ const AceEditorWrapper = ({ dbId: queryEditor.dbId, catalog: queryEditor.catalog, schema: queryEditor.schema, + tabViewId: queryEditor.tabViewId, }, !autocomplete, ); diff --git a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useKeywords.ts b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useKeywords.ts index 99e99125133..548c74e463d 100644 --- a/superset-frontend/src/SqlLab/components/AceEditorWrapper/useKeywords.ts +++ b/superset-frontend/src/SqlLab/components/AceEditorWrapper/useKeywords.ts @@ -44,6 +44,7 @@ type Params = { dbId?: string | number; catalog?: string | null; schema?: string; + tabViewId?: string; }; const EMPTY_LIST = [] as typeof sqlKeywords; @@ -59,7 +60,7 @@ const getHelperText = (value: string) => const extensionsRegistry = getExtensionsRegistry(); export function useKeywords( - { queryEditorId, dbId, catalog, schema }: Params, + { queryEditorId, dbId, catalog, schema, tabViewId }: Params, skip = false, ) { const useCustomKeywords = extensionsRegistry.get( @@ -147,7 +148,12 @@ export function useKeywords( const insertMatch = useEffectEvent((editor: Editor, data: any) => { if (data.meta === 'table') { dispatch( - addTable({ id: queryEditorId, dbId }, data.value, catalog, schema), + addTable( + { id: queryEditorId, dbId, tabViewId }, + data.value, + catalog, + schema, + ), ); } diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx index a51f312b608..93bc2fd5a02 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx @@ -84,6 +84,7 @@ const SqlEditorLeftBar = ({ 'dbId', 'catalog', 'schema', + 'tabViewId', ]); const [_emptyResultsWithSearch, setEmptyResultsWithSearch] = useState(false);