fix(sqllab): inactive leftbar selector on empty state (#38833)

(cherry picked from commit cfa1aba1e0)
This commit is contained in:
JUST.in DO IT
2026-03-26 08:57:16 -07:00
committed by Michael S. Molina
parent 686fa44a5f
commit bd552209e7
7 changed files with 94 additions and 28 deletions

View File

@@ -33,6 +33,7 @@ import {
} from 'src/SqlLab/fixtures';
import { SupersetClient, isFeatureEnabled } from '@superset-ui/core';
import { ADD_TOAST } from 'src/components/MessageToasts/actions';
import { EMPTY_STATE_QE_ID } from 'src/SqlLab/hooks/useQueryEditor';
import { ToastType } from '../../components/MessageToasts/types';
const isFeatureEnabledMock = isFeatureEnabled as unknown as jest.Mock;
@@ -882,6 +883,44 @@ describe('async actions', () => {
request(store.dispatch, store.getState, undefined);
expect(store.getActions()).toEqual(expectedActions);
});
test('creates a new query editor from the saved state in the empty tab', () => {
const unsavedEmptyTabState = {
id: EMPTY_STATE_QE_ID,
dbId: 2,
catalog: 'test_catalog',
schema: 'test_schema',
};
const store = mockStore({
...initialState,
sqlLab: {
...initialState.sqlLab,
tabHistory: [EMPTY_STATE_QE_ID],
unsavedQueryEditor: unsavedEmptyTabState,
},
});
const expectedActions = [
{
type: actions.ADD_QUERY_EDITOR,
queryEditor: {
id: 'abcd',
immutableId: 'abcd',
sql: expect.stringContaining('SELECT ...'),
name: 'Untitled Query 4',
dbId: unsavedEmptyTabState.dbId,
catalog: unsavedEmptyTabState.catalog,
schema: unsavedEmptyTabState.schema,
inLocalStorage: true,
autorun: false,
queryLimit: initialState.common.conf.DEFAULT_SQLLAB_LIMIT,
loaded: true,
},
},
];
const request = actions.addNewQueryEditor();
request(store.dispatch, store.getState, undefined);
expect(store.getActions()).toEqual(expectedActions);
});
});
});

View File

@@ -47,6 +47,7 @@ import { newQueryTabName } from '../utils/newQueryTabName';
import getInitialState from '../reducers/getInitialState';
import { rehydratePersistedState } from '../utils/reduxStateToLocalStorageHelper';
import { PREVIEW_QUERY_LIMIT } from '../constants';
import { EMPTY_STATE_QE_ID } from '../hooks/useQueryEditor';
// Type definitions for SqlLab actions
export interface Query {
@@ -754,7 +755,7 @@ export function addNewQueryEditor(): SqlLabThunkAction<SqlLabAction> {
const defaultDbId = common.conf.SQLLAB_DEFAULT_DBID as number | undefined;
const activeQueryEditor = queryEditors.find(
(qe: QueryEditor) => qe.id === tabHistory[tabHistory.length - 1],
);
) ?? { id: EMPTY_STATE_QE_ID };
const dbIds = Object.values(databases).map(
(database: { id: number }) => database.id,
);

View File

@@ -32,6 +32,8 @@ import {
defaultQueryEditor,
extraQueryEditor2,
} from 'src/SqlLab/fixtures';
import { EMPTY_STATE_QE_ID } from 'src/SqlLab/hooks/useQueryEditor';
import * as useDatabaseSelectorModule from '../SqlEditorTopBar/useDatabaseSelector';
import type { RootState } from 'src/views/store';
import type { Store } from 'redux';
@@ -235,3 +237,16 @@ test('ignore schema api when current schema is deprecated', async () => {
]),
);
});
test('uses EMPTY_STATE_QE_ID when queryEditorId is empty', async () => {
const useDatabaseSelectorSpy = jest.spyOn(
useDatabaseSelectorModule,
'default',
);
await renderAndWait({ queryEditorId: '' }, undefined, initialState);
expect(useDatabaseSelectorSpy).toHaveBeenCalledWith(EMPTY_STATE_QE_ID);
useDatabaseSelectorSpy.mockRestore();
});

View File

@@ -32,6 +32,7 @@ import { t } from '@apache-superset/core/translation';
import { styled, css } from '@apache-superset/core/theme';
import type { SchemaOption, CatalogOption } from 'src/hooks/apiResources';
import { DatabaseSelector, type DatabaseObject } from 'src/components';
import { EMPTY_STATE_QE_ID } from 'src/SqlLab/hooks/useQueryEditor';
import useDatabaseSelector from '../SqlEditorTopBar/useDatabaseSelector';
import TableExploreTree from '../TableExploreTree';
@@ -63,7 +64,8 @@ const StyledDivider = styled.div`
`;
const SqlEditorLeftBar = ({ queryEditorId }: SqlEditorLeftBarProps) => {
const dbSelectorProps = useDatabaseSelector(queryEditorId);
const activeQEId = queryEditorId || EMPTY_STATE_QE_ID;
const dbSelectorProps = useDatabaseSelector(activeQEId);
const { db, catalog, schema, onDbChange, onCatalogChange, onSchemaChange } =
dbSelectorProps;
@@ -198,7 +200,7 @@ const SqlEditorLeftBar = ({ queryEditorId }: SqlEditorLeftBarProps) => {
/>
</Popover>
<StyledDivider />
<TableExploreTree queryEditorId={queryEditorId} />
<TableExploreTree queryEditorId={activeQEId} />
{shouldShowReset && (
<Button
buttonSize="small"

View File

@@ -21,6 +21,8 @@ import { useMemo } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import { SqlLabRootState, QueryEditor } from 'src/SqlLab/types';
export const EMPTY_STATE_QE_ID = 'tmp_qe_id';
export default function useQueryEditor<T extends keyof QueryEditor>(
sqlEditorId: string,
attributes: ReadonlyArray<T>,
@@ -43,6 +45,7 @@ export default function useQueryEditor<T extends keyof QueryEditor>(
{
...queryEditors[queryEditorsById[sqlEditorId]],
...(sqlEditorId === unsavedQueryEditor?.id && unsavedQueryEditor),
...(sqlEditorId === EMPTY_STATE_QE_ID && { id: sqlEditorId }),
},
['id'].concat(attributes),
) as Pick<QueryEditor, T | 'id'>,

View File

@@ -42,7 +42,10 @@ function alterUnsavedQueryEditorState(
id: string,
silent = false,
): Partial<SqlLabState> {
if (state.tabHistory[state.tabHistory.length - 1] !== id) {
if (
state.tabHistory.length > 0 &&
state.tabHistory[state.tabHistory.length - 1] !== id
) {
const { queryEditors } = alterInArr(
state,
'queryEditors',