You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ju...@apache.org on 2023/12/15 18:13:49 UTC

(superset) branch fix--3.1.0rc2 created (now 1f96a610cb)

This is an automated email from the ASF dual-hosted git repository.

justinpark pushed a change to branch fix--3.1.0rc2
in repository https://gitbox.apache.org/repos/asf/superset.git


      at 1f96a610cb Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)"

This branch includes the following new commits:

     new 1f96a610cb Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)"

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)"

Posted by ju...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

justinpark pushed a commit to branch fix--3.1.0rc2
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 1f96a610cbe114c786b644f494422fc48342f80c
Author: justinpark <ju...@gmail.com>
AuthorDate: Fri Dec 15 10:10:53 2023 -0800

    Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)"
    
    This reverts commit 77c73b63db8fe9574db129e85b4393fa33f283a6.
---
 .../SqlLab/components/QueryAutoRefresh/index.tsx   |   2 +-
 .../components/QueryHistory/QueryHistory.test.tsx  |   5 +-
 .../src/SqlLab/components/QueryHistory/index.tsx   |  29 +-
 .../src/SqlLab/components/QueryTable/index.tsx     |   3 +-
 .../SqlLab/components/ResultSet/ResultSet.test.tsx | 333 +++++----------------
 .../src/SqlLab/components/ResultSet/index.tsx      |  52 +---
 .../SqlLab/components/SouthPane/Results.test.tsx   | 135 ---------
 .../src/SqlLab/components/SouthPane/Results.tsx    | 106 -------
 .../SqlLab/components/SouthPane/SouthPane.test.tsx |  81 ++---
 .../src/SqlLab/components/SouthPane/index.tsx      | 174 +++++++----
 .../SqlLab/components/SqlEditor/SqlEditor.test.tsx |   7 +-
 superset-frontend/src/SqlLab/reducers/sqlLab.js    |  17 +-
 .../src/SqlLab/reducers/sqlLab.test.js             |   5 +-
 13 files changed, 274 insertions(+), 675 deletions(-)

diff --git a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx
index a2ffcf85cb..f4808f52fd 100644
--- a/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx
@@ -45,7 +45,7 @@ export interface QueryAutoRefreshProps {
 
 // returns true if the Query.state matches one of the specifc values indicating the query is still processing on server
 export const isQueryRunning = (q: Query): boolean =>
-  runningQueryStateList.includes(q?.state) && !q?.resultsKey;
+  runningQueryStateList.includes(q?.state);
 
 // returns true if at least one query is running and within the max age to poll timeframe
 export const shouldCheckForQueries = (queryList: QueryDictionary): boolean => {
diff --git a/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx b/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx
index ad1881b5d9..6fd84a0d2a 100644
--- a/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryHistory/QueryHistory.test.tsx
@@ -19,10 +19,9 @@
 import React from 'react';
 import { render, screen } from 'spec/helpers/testing-library';
 import QueryHistory from 'src/SqlLab/components/QueryHistory';
-import { initialState } from 'src/SqlLab/fixtures';
 
 const mockedProps = {
-  queryEditorId: 123,
+  queries: [],
   displayLimit: 1000,
   latestQueryId: 'yhMUZCGb',
 };
@@ -33,7 +32,7 @@ const setup = (overrides = {}) => (
 
 describe('QueryHistory', () => {
   it('Renders an empty state for query history', () => {
-    render(setup(), { useRedux: true, initialState });
+    render(setup());
 
     const emptyStateText = screen.getByText(
       /run a query to display query history/i,
diff --git a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
index 311a125d55..cab1160144 100644
--- a/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
@@ -16,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import React, { useMemo } from 'react';
-import { shallowEqual, useSelector } from 'react-redux';
+import React from 'react';
 import { EmptyStateMedium } from 'src/components/EmptyState';
-import { t, styled } from '@superset-ui/core';
+import { t, styled, QueryResponse } from '@superset-ui/core';
 import QueryTable from 'src/SqlLab/components/QueryTable';
-import { SqlLabRootState } from 'src/SqlLab/types';
 
 interface QueryHistoryProps {
-  queryEditorId: string | number;
+  queries: QueryResponse[];
   displayLimit: number;
   latestQueryId: string | undefined;
 }
@@ -41,23 +39,11 @@ const StyledEmptyStateWrapper = styled.div`
 `;
 
 const QueryHistory = ({
-  queryEditorId,
+  queries,
   displayLimit,
   latestQueryId,
-}: QueryHistoryProps) => {
-  const queries = useSelector(
-    ({ sqlLab: { queries } }: SqlLabRootState) => queries,
-    shallowEqual,
-  );
-  const editorQueries = useMemo(
-    () =>
-      Object.values(queries).filter(
-        ({ sqlEditorId }) => String(sqlEditorId) === String(queryEditorId),
-      ),
-    [queries, queryEditorId],
-  );
-
-  return editorQueries.length > 0 ? (
+}: QueryHistoryProps) =>
+  queries.length > 0 ? (
     <QueryTable
       columns={[
         'state',
@@ -69,7 +55,7 @@ const QueryHistory = ({
         'results',
         'actions',
       ]}
-      queries={editorQueries}
+      queries={queries}
       displayLimit={displayLimit}
       latestQueryId={latestQueryId}
     />
@@ -81,6 +67,5 @@ const QueryHistory = ({
       />
     </StyledEmptyStateWrapper>
   );
-};
 
 export default QueryHistory;
diff --git a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
index 3282a939ef..5dc8a43c19 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
@@ -251,7 +251,8 @@ const QueryTable = ({
               modalBody={
                 <ResultSet
                   showSql
-                  queryId={query.id}
+                  user={user}
+                  query={query}
                   height={400}
                   displayLimit={displayLimit}
                   defaultQueryLimit={1000}
diff --git a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
index e5844fed5c..d823c586f7 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx
@@ -37,91 +37,65 @@ import {
 
 const mockedProps = {
   cache: true,
-  queryId: queries[0].id,
+  query: queries[0],
   height: 140,
   database: { allows_virtual_table_explore: true },
-  displayLimit: 1000,
+  user,
   defaultQueryLimit: 1000,
 };
-const stoppedQueryState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [stoppedQuery.id]: stoppedQuery,
-    },
-  },
-};
-const runningQueryState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [runningQuery.id]: runningQuery,
-    },
-  },
-};
-const fetchingQueryState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [mockedProps.queryId]: {
-        dbId: 1,
-        cached: false,
-        ctas: false,
-        id: 'ryhHUZCGb',
-        progress: 100,
-        state: 'fetching',
-        startDttm: Date.now() - 500,
-      },
-    },
+const stoppedQueryProps = { ...mockedProps, query: stoppedQuery };
+const runningQueryProps = { ...mockedProps, query: runningQuery };
+const fetchingQueryProps = {
+  ...mockedProps,
+  query: {
+    dbId: 1,
+    cached: false,
+    ctas: false,
+    id: 'ryhHUZCGb',
+    progress: 100,
+    state: 'fetching',
+    startDttm: Date.now() - 500,
   },
 };
-const cachedQueryState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [cachedQuery.id]: cachedQuery,
-    },
-  },
+const cachedQueryProps = { ...mockedProps, query: cachedQuery };
+const failedQueryWithErrorMessageProps = {
+  ...mockedProps,
+  query: failedQueryWithErrorMessage,
 };
-const failedQueryWithErrorMessageState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [failedQueryWithErrorMessage.id]: failedQueryWithErrorMessage,
-    },
-  },
+const failedQueryWithErrorsProps = {
+  ...mockedProps,
+  query: failedQueryWithErrors,
 };
-const failedQueryWithErrorsState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState.sqlLab,
-    queries: {
-      [failedQueryWithErrors.id]: failedQueryWithErrors,
+const newProps = {
+  query: {
+    cached: false,
+    resultsKey: 'new key',
+    results: {
+      data: [{ a: 1 }],
     },
   },
 };
-
-const newProps = {
-  displayLimit: 1001,
-};
 const asyncQueryProps = {
   ...mockedProps,
   database: { allow_run_async: true },
 };
-
-const reRunQueryEndpoint = 'glob:*/api/v1/sqllab/execute/';
+const asyncRefetchDataPreviewProps = {
+  ...asyncQueryProps,
+  query: {
+    state: 'success',
+    results: undefined,
+    isDataPreview: true,
+  },
+};
+const asyncRefetchResultsTableProps = {
+  ...asyncQueryProps,
+  query: {
+    state: 'success',
+    results: undefined,
+    resultsKey: 'async results key',
+  },
+};
 fetchMock.get('glob:*/api/v1/dataset/?*', { result: [] });
-fetchMock.post(reRunQueryEndpoint, { result: [] });
-fetchMock.get('glob:*/api/v1/sqllab/results/*', { result: [] });
-
-beforeEach(() => {
-  fetchMock.resetHistory();
-});
 
 const middlewares = [thunk];
 const mockStore = configureStore(middlewares);
@@ -133,47 +107,25 @@ const setup = (props?: any, store?: Store) =>
 
 describe('ResultSet', () => {
   test('renders a Table', async () => {
-    const { getByTestId } = setup(
-      mockedProps,
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [queries[0].id]: queries[0],
-          },
-        },
-      }),
-    );
+    const { getByTestId } = setup(mockedProps, mockStore(initialState));
     const table = getByTestId('table-container');
     expect(table).toBeInTheDocument();
   });
 
   test('should render success query', async () => {
-    const query = queries[0];
     const { queryAllByText, getByTestId } = setup(
       mockedProps,
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [query.id]: query,
-          },
-        },
-      }),
+      mockStore(initialState),
     );
 
     const table = getByTestId('table-container');
     expect(table).toBeInTheDocument();
 
     const firstColumn = queryAllByText(
-      query.results?.columns[0].column_name ?? '',
+      mockedProps.query.results?.columns[0].column_name ?? '',
     )[0];
     const secondColumn = queryAllByText(
-      query.results?.columns[1].column_name ?? '',
+      mockedProps.query.results?.columns[1].column_name ?? '',
     )[0];
     expect(firstColumn).toBeInTheDocument();
     expect(secondColumn).toBeInTheDocument();
@@ -183,24 +135,12 @@ describe('ResultSet', () => {
   });
 
   test('should render empty results', async () => {
-    const query = {
-      ...queries[0],
-      results: { data: [] },
+    const props = {
+      ...mockedProps,
+      query: { ...mockedProps.query, results: { data: [] } },
     };
     await waitFor(() => {
-      setup(
-        mockedProps,
-        mockStore({
-          ...initialState,
-          user,
-          sqlLab: {
-            ...initialState.sqlLab,
-            queries: {
-              [query.id]: query,
-            },
-          },
-        }),
-      );
+      setup(props, mockStore(initialState));
     });
 
     const alert = screen.getByRole('alert');
@@ -209,70 +149,42 @@ describe('ResultSet', () => {
   });
 
   test('should call reRunQuery if timed out', async () => {
-    const query = {
-      ...queries[0],
-      errorMessage: 'Your session timed out',
+    const store = mockStore(initialState);
+    const propsWithError = {
+      ...mockedProps,
+      query: { ...queries[0], errorMessage: 'Your session timed out' },
     };
-    const store = mockStore({
-      ...initialState,
-      user,
-      sqlLab: {
-        ...initialState.sqlLab,
-        queries: {
-          [query.id]: query,
-        },
-      },
-    });
 
-    expect(fetchMock.calls(reRunQueryEndpoint)).toHaveLength(0);
-    setup(mockedProps, store);
+    setup(propsWithError, store);
     expect(store.getActions()).toHaveLength(1);
     expect(store.getActions()[0].query.errorMessage).toEqual(
       'Your session timed out',
     );
     expect(store.getActions()[0].type).toEqual('START_QUERY');
-    await waitFor(() =>
-      expect(fetchMock.calls(reRunQueryEndpoint)).toHaveLength(1),
-    );
   });
 
   test('should not call reRunQuery if no error', async () => {
-    const query = queries[0];
-    const store = mockStore({
-      ...initialState,
-      user,
-      sqlLab: {
-        ...initialState.sqlLab,
-        queries: {
-          [query.id]: query,
-        },
-      },
-    });
+    const store = mockStore(initialState);
     setup(mockedProps, store);
     expect(store.getActions()).toEqual([]);
-    expect(fetchMock.calls(reRunQueryEndpoint)).toHaveLength(0);
   });
 
   test('should render cached query', async () => {
-    const store = mockStore(cachedQueryState);
-    const { rerender } = setup(
-      { ...mockedProps, queryId: cachedQuery.id },
-      store,
-    );
+    const store = mockStore(initialState);
+    const { rerender } = setup(cachedQueryProps, store);
 
     // @ts-ignore
-    rerender(<ResultSet {...mockedProps} {...newProps} />);
-    expect(store.getActions()).toHaveLength(1);
-    expect(store.getActions()[0].query.results).toEqual(cachedQuery.results);
+    rerender(<ResultSet {...newProps} />);
+    expect(store.getActions()).toHaveLength(2);
+    expect(store.getActions()[0].query.results).toEqual(
+      cachedQueryProps.query.results,
+    );
     expect(store.getActions()[0].type).toEqual('CLEAR_QUERY_RESULTS');
   });
 
   test('should render stopped query', async () => {
     await waitFor(() => {
-      setup(
-        { ...mockedProps, queryId: stoppedQuery.id },
-        mockStore(stoppedQueryState),
-      );
+      setup(stoppedQueryProps, mockStore(initialState));
     });
 
     const alert = screen.getByRole('alert');
@@ -280,18 +192,15 @@ describe('ResultSet', () => {
   });
 
   test('should render running/pending/fetching query', async () => {
-    const { getByTestId } = setup(
-      { ...mockedProps, queryId: runningQuery.id },
-      mockStore(runningQueryState),
-    );
+    const { getByTestId } = setup(runningQueryProps, mockStore(initialState));
     const progressBar = getByTestId('progress-bar');
     expect(progressBar).toBeInTheDocument();
   });
 
   test('should render fetching w/ 100 progress query', async () => {
     const { getByRole, getByText } = setup(
-      mockedProps,
-      mockStore(fetchingQueryState),
+      fetchingQueryProps,
+      mockStore(initialState),
     );
     const loading = getByRole('status');
     expect(loading).toBeInTheDocument();
@@ -300,10 +209,7 @@ describe('ResultSet', () => {
 
   test('should render a failed query with an error message', async () => {
     await waitFor(() => {
-      setup(
-        { ...mockedProps, queryId: failedQueryWithErrorMessage.id },
-        mockStore(failedQueryWithErrorMessageState),
-      );
+      setup(failedQueryWithErrorMessageProps, mockStore(initialState));
     });
 
     expect(screen.getByText('Database error')).toBeInTheDocument();
@@ -312,129 +218,44 @@ describe('ResultSet', () => {
 
   test('should render a failed query with an errors object', async () => {
     await waitFor(() => {
-      setup(
-        { ...mockedProps, queryId: failedQueryWithErrors.id },
-        mockStore(failedQueryWithErrorsState),
-      );
+      setup(failedQueryWithErrorsProps, mockStore(initialState));
     });
     expect(screen.getByText('Database error')).toBeInTheDocument();
   });
 
   test('renders if there is no limit in query.results but has queryLimit', async () => {
-    const query = {
-      ...queries[0],
-    };
-    await waitFor(() => {
-      setup(
-        mockedProps,
-        mockStore({
-          ...initialState,
-          user,
-          sqlLab: {
-            ...initialState.sqlLab,
-            queries: {
-              [query.id]: query,
-            },
-          },
-        }),
-      );
-    });
     const { getByRole } = setup(mockedProps, mockStore(initialState));
     expect(getByRole('table')).toBeInTheDocument();
   });
 
   test('renders if there is a limit in query.results but not queryLimit', async () => {
-    const props = { ...mockedProps, queryId: queryWithNoQueryLimit.id };
-    const { getByRole } = setup(
-      props,
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [queryWithNoQueryLimit.id]: queryWithNoQueryLimit,
-          },
-        },
-      }),
-    );
+    const props = { ...mockedProps, query: queryWithNoQueryLimit };
+    const { getByRole } = setup(props, mockStore(initialState));
     expect(getByRole('table')).toBeInTheDocument();
   });
 
   test('Async queries - renders "Fetch data preview" button when data preview has no results', () => {
-    const asyncRefetchDataPreviewQuery = {
-      ...queries[0],
-      state: 'success',
-      results: undefined,
-      isDataPreview: true,
-    };
-    setup(
-      { ...asyncQueryProps, queryId: asyncRefetchDataPreviewQuery.id },
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [asyncRefetchDataPreviewQuery.id]: asyncRefetchDataPreviewQuery,
-          },
-        },
-      }),
-    );
+    setup(asyncRefetchDataPreviewProps, mockStore(initialState));
     expect(
       screen.getByRole('button', {
         name: /fetch data preview/i,
       }),
     ).toBeVisible();
-    expect(screen.queryByRole('table')).toBe(null);
+    expect(screen.queryByRole('grid')).toBe(null);
   });
 
   test('Async queries - renders "Refetch results" button when a query has no results', () => {
-    const asyncRefetchResultsTableQuery = {
-      ...queries[0],
-      state: 'success',
-      results: undefined,
-      resultsKey: 'async results key',
-    };
-
-    setup(
-      { ...asyncQueryProps, queryId: asyncRefetchResultsTableQuery.id },
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [asyncRefetchResultsTableQuery.id]: asyncRefetchResultsTableQuery,
-          },
-        },
-      }),
-    );
+    setup(asyncRefetchResultsTableProps, mockStore(initialState));
     expect(
       screen.getByRole('button', {
         name: /refetch results/i,
       }),
     ).toBeVisible();
-    expect(screen.queryByRole('table')).toBe(null);
+    expect(screen.queryByRole('grid')).toBe(null);
   });
 
   test('Async queries - renders on the first call', () => {
-    const query = {
-      ...queries[0],
-    };
-    setup(
-      { ...asyncQueryProps, queryId: query.id },
-      mockStore({
-        ...initialState,
-        user,
-        sqlLab: {
-          ...initialState.sqlLab,
-          queries: {
-            [query.id]: query,
-          },
-        },
-      }),
-    );
+    setup(asyncQueryProps, mockStore(initialState));
     expect(screen.getByRole('table')).toBeVisible();
     expect(
       screen.queryByRole('button', {
diff --git a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
index 69e4508434..58e55a1df7 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet/index.tsx
@@ -17,14 +17,14 @@
  * under the License.
  */
 import React, { useCallback, useEffect, useState } from 'react';
-import { shallowEqual, useDispatch, useSelector } from 'react-redux';
+import { useDispatch } from 'react-redux';
 import { useHistory } from 'react-router-dom';
-import pick from 'lodash/pick';
 import ButtonGroup from 'src/components/ButtonGroup';
 import Alert from 'src/components/Alert';
 import Button from 'src/components/Button';
 import shortid from 'shortid';
 import {
+  QueryResponse,
   QueryState,
   styled,
   t,
@@ -41,7 +41,8 @@ import {
   ISimpleColumn,
   SaveDatasetModal,
 } from 'src/SqlLab/components/SaveDatasetModal';
-import { EXPLORE_CHART_DEFAULT, SqlLabRootState } from 'src/SqlLab/types';
+import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
+import { EXPLORE_CHART_DEFAULT } from 'src/SqlLab/types';
 import { mountExploreUrl } from 'src/explore/exploreUtils';
 import { postFormData } from 'src/explore/exploreUtils/formData';
 import ProgressBar from 'src/components/ProgressBar';
@@ -81,11 +82,12 @@ export interface ResultSetProps {
   database?: Record<string, any>;
   displayLimit: number;
   height: number;
-  queryId: string;
+  query: QueryResponse;
   search?: boolean;
   showSql?: boolean;
   showSqlInline?: boolean;
   visualize?: boolean;
+  user: UserWithPermissionsAndRoles;
   defaultQueryLimit: number;
 }
 
@@ -143,44 +145,14 @@ const ResultSet = ({
   database = {},
   displayLimit,
   height,
-  queryId,
+  query,
   search = true,
   showSql = false,
   showSqlInline = false,
   visualize = true,
+  user,
   defaultQueryLimit,
 }: ResultSetProps) => {
-  const user = useSelector(({ user }: SqlLabRootState) => user, shallowEqual);
-  const query = useSelector(
-    ({ sqlLab: { queries } }: SqlLabRootState) =>
-      pick(queries[queryId], [
-        'id',
-        'errorMessage',
-        'cached',
-        'results',
-        'resultsKey',
-        'dbId',
-        'tab',
-        'sql',
-        'templateParams',
-        'schema',
-        'rows',
-        'queryLimit',
-        'limitingFactor',
-        'trackingUrl',
-        'state',
-        'errors',
-        'link',
-        'ctas',
-        'ctas_method',
-        'tempSchema',
-        'tempTable',
-        'isDataPreview',
-        'progress',
-        'extra',
-      ]),
-    shallowEqual,
-  );
   const ResultTable =
     extensionsRegistry.get('sqleditor.extension.resultTable') ??
     FilterableTable;
@@ -207,8 +179,8 @@ const ResultSet = ({
     reRunQueryIfSessionTimeoutErrorOnMount();
   }, [reRunQueryIfSessionTimeoutErrorOnMount]);
 
-  const fetchResults = (q: typeof query) => {
-    dispatch(fetchQueryResults(q, displayLimit));
+  const fetchResults = (query: QueryResponse) => {
+    dispatch(fetchQueryResults(query, displayLimit));
   };
 
   const prevQuery = usePrevious(query);
@@ -507,7 +479,7 @@ const ResultSet = ({
       <ResultlessStyles>
         <ErrorMessageWithStackTrace
           title={t('Database error')}
-          error={query?.extra?.errors?.[0] || query?.errors?.[0]}
+          error={query?.errors?.[0]}
           subtitle={<MonospaceDiv>{query.errorMessage}</MonospaceDiv>}
           copyText={query.errorMessage || undefined}
           link={query.link}
@@ -690,4 +662,4 @@ const ResultSet = ({
   );
 };
 
-export default React.memo(ResultSet);
+export default ResultSet;
diff --git a/superset-frontend/src/SqlLab/components/SouthPane/Results.test.tsx b/superset-frontend/src/SqlLab/components/SouthPane/Results.test.tsx
deleted file mode 100644
index c70c039fe5..0000000000
--- a/superset-frontend/src/SqlLab/components/SouthPane/Results.test.tsx
+++ /dev/null
@@ -1,135 +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.
- */
-import React from 'react';
-import { render } from 'spec/helpers/testing-library';
-import { initialState, table, defaultQueryEditor } from 'src/SqlLab/fixtures';
-import { denormalizeTimestamp } from '@superset-ui/core';
-import { LOCALSTORAGE_MAX_QUERY_AGE_MS } from 'src/SqlLab/constants';
-import Results from './Results';
-
-const mockedProps = {
-  queryEditorId: defaultQueryEditor.id,
-  latestQueryId: 'LCly_kkIN',
-  height: 1,
-  displayLimit: 1,
-  defaultQueryLimit: 100,
-};
-
-const mockedEmptyProps = {
-  queryEditorId: 'random_id',
-  latestQueryId: 'empty_query_id',
-  height: 100,
-  displayLimit: 100,
-  defaultQueryLimit: 100,
-};
-
-const mockedExpiredProps = {
-  ...mockedEmptyProps,
-  latestQueryId: 'expired_query_id',
-};
-
-const latestQueryProgressMsg = 'LATEST QUERY MESSAGE - LCly_kkIN';
-const expireDateTime = Date.now() - LOCALSTORAGE_MAX_QUERY_AGE_MS - 1;
-
-const mockState = {
-  ...initialState,
-  sqlLab: {
-    ...initialState,
-    offline: false,
-    tables: [
-      {
-        ...table,
-        dataPreviewQueryId: '2g2_iRFMl',
-        queryEditorId: defaultQueryEditor.id,
-      },
-    ],
-    databases: {},
-    queries: {
-      LCly_kkIN: {
-        cached: false,
-        changed_on: denormalizeTimestamp(new Date().toISOString()),
-        db: 'main',
-        dbId: 1,
-        id: 'LCly_kkIN',
-        startDttm: Date.now(),
-        sqlEditorId: defaultQueryEditor.id,
-        extra: { progress: latestQueryProgressMsg },
-        sql: 'select * from table1',
-      },
-      lXJa7F9_r: {
-        cached: false,
-        changed_on: denormalizeTimestamp(new Date(1559238500401).toISOString()),
-        db: 'main',
-        dbId: 1,
-        id: 'lXJa7F9_r',
-        startDttm: 1559238500401,
-        sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table2',
-      },
-      '2g2_iRFMl': {
-        cached: false,
-        changed_on: denormalizeTimestamp(new Date(1559238506925).toISOString()),
-        db: 'main',
-        dbId: 1,
-        id: '2g2_iRFMl',
-        startDttm: 1559238506925,
-        sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table3',
-      },
-      expired_query_id: {
-        cached: false,
-        changed_on: denormalizeTimestamp(
-          new Date(expireDateTime).toISOString(),
-        ),
-        db: 'main',
-        dbId: 1,
-        id: 'expired_query_id',
-        startDttm: expireDateTime,
-        sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table4',
-      },
-    },
-  },
-};
-
-test('Renders an empty state for results', async () => {
-  const { getByText } = render(<Results {...mockedEmptyProps} />, {
-    useRedux: true,
-    initialState: mockState,
-  });
-  const emptyStateText = getByText(/run a query to display results/i);
-  expect(emptyStateText).toBeVisible();
-});
-
-test('Renders an empty state for expired results', async () => {
-  const { getByText } = render(<Results {...mockedExpiredProps} />, {
-    useRedux: true,
-    initialState: mockState,
-  });
-  const emptyStateText = getByText(/run a query to display results/i);
-  expect(emptyStateText).toBeVisible();
-});
-
-test('should pass latest query down to ResultSet component', async () => {
-  const { getByText } = render(<Results {...mockedProps} />, {
-    useRedux: true,
-    initialState: mockState,
-  });
-  expect(getByText(latestQueryProgressMsg)).toBeVisible();
-});
diff --git a/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx b/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx
deleted file mode 100644
index 4e1b6219ae..0000000000
--- a/superset-frontend/src/SqlLab/components/SouthPane/Results.tsx
+++ /dev/null
@@ -1,106 +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.
- */
-import React from 'react';
-import { shallowEqual, useSelector } from 'react-redux';
-import Alert from 'src/components/Alert';
-import { EmptyStateMedium } from 'src/components/EmptyState';
-import { FeatureFlag, styled, t, isFeatureEnabled } from '@superset-ui/core';
-
-import { SqlLabRootState } from 'src/SqlLab/types';
-import ResultSet from '../ResultSet';
-import { LOCALSTORAGE_MAX_QUERY_AGE_MS } from '../../constants';
-
-const EXTRA_HEIGHT_RESULTS = 8; // we need extra height in RESULTS tab. because the height from props was calculated based on PREVIEW tab.
-
-type Props = {
-  latestQueryId: string;
-  height: number;
-  displayLimit: number;
-  defaultQueryLimit: number;
-};
-
-const StyledEmptyStateWrapper = styled.div`
-  height: 100%;
-  .ant-empty-image img {
-    margin-right: 28px;
-  }
-
-  p {
-    margin-right: 28px;
-  }
-`;
-
-const Results: React.FC<Props> = ({
-  latestQueryId,
-  height,
-  displayLimit,
-  defaultQueryLimit,
-}) => {
-  const databases = useSelector(
-    ({ sqlLab: { databases } }: SqlLabRootState) => databases,
-    shallowEqual,
-  );
-  const latestQuery = useSelector(
-    ({ sqlLab: { queries } }: SqlLabRootState) => queries[latestQueryId || ''],
-    shallowEqual,
-  );
-
-  if (
-    !latestQuery ||
-    Date.now() - latestQuery.startDttm > LOCALSTORAGE_MAX_QUERY_AGE_MS
-  ) {
-    return (
-      <StyledEmptyStateWrapper>
-        <EmptyStateMedium
-          title={t('Run a query to display results')}
-          image="document.svg"
-        />
-      </StyledEmptyStateWrapper>
-    );
-  }
-
-  if (
-    isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) &&
-    latestQuery.state === 'success' &&
-    !latestQuery.resultsKey &&
-    !latestQuery.results
-  ) {
-    return (
-      <Alert
-        type="warning"
-        message={t('No stored results found, you need to re-run your query')}
-      />
-    );
-  }
-
-  return (
-    <ResultSet
-      search
-      queryId={latestQuery.id}
-      height={height + EXTRA_HEIGHT_RESULTS}
-      database={databases[latestQuery.dbId]}
-      displayLimit={displayLimit}
-      defaultQueryLimit={defaultQueryLimit}
-      showSql
-      showSqlInline
-    />
-  );
-};
-
-export default Results;
diff --git a/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.tsx b/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.tsx
index c978a4ca32..80a102ff21 100644
--- a/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.tsx
+++ b/superset-frontend/src/SqlLab/components/SouthPane/SouthPane.test.tsx
@@ -17,12 +17,15 @@
  * under the License.
  */
 import React from 'react';
-import { render } from 'spec/helpers/testing-library';
-import SouthPane from 'src/SqlLab/components/SouthPane';
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import { render, screen, waitFor } from 'spec/helpers/testing-library';
+import SouthPane, { SouthPaneProps } from 'src/SqlLab/components/SouthPane';
 import '@testing-library/jest-dom/extend-expect';
 import { STATUS_OPTIONS } from 'src/SqlLab/constants';
 import { initialState, table, defaultQueryEditor } from 'src/SqlLab/fixtures';
 import { denormalizeTimestamp } from '@superset-ui/core';
+import { Store } from 'redux';
 
 const mockedProps = {
   queryEditorId: defaultQueryEditor.id,
@@ -34,32 +37,29 @@ const mockedProps = {
 
 const mockedEmptyProps = {
   queryEditorId: 'random_id',
-  latestQueryId: 'empty_query_id',
+  latestQueryId: '',
   height: 100,
   displayLimit: 100,
   defaultQueryLimit: 100,
 };
 
+jest.mock('src/SqlLab/components/SqlEditorLeftBar', () => jest.fn());
+
 const latestQueryProgressMsg = 'LATEST QUERY MESSAGE - LCly_kkIN';
 
-const mockState = {
+const middlewares = [thunk];
+const mockStore = configureStore(middlewares);
+const store = mockStore({
   ...initialState,
   sqlLab: {
-    ...initialState.sqlLab,
+    ...initialState,
     offline: false,
     tables: [
       {
         ...table,
-        name: 'table3',
         dataPreviewQueryId: '2g2_iRFMl',
         queryEditorId: defaultQueryEditor.id,
       },
-      {
-        ...table,
-        name: 'table4',
-        dataPreviewQueryId: 'erWdqEWPm',
-        queryEditorId: defaultQueryEditor.id,
-      },
     ],
     databases: {},
     queries: {
@@ -72,7 +72,6 @@ const mockState = {
         startDttm: Date.now(),
         sqlEditorId: defaultQueryEditor.id,
         extra: { progress: latestQueryProgressMsg },
-        sql: 'select * from table1',
       },
       lXJa7F9_r: {
         cached: false,
@@ -82,7 +81,6 @@ const mockState = {
         id: 'lXJa7F9_r',
         startDttm: 1559238500401,
         sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table2',
       },
       '2g2_iRFMl': {
         cached: false,
@@ -92,7 +90,6 @@ const mockState = {
         id: '2g2_iRFMl',
         startDttm: 1559238506925,
         sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table3',
       },
       erWdqEWPm: {
         cached: false,
@@ -102,38 +99,44 @@ const mockState = {
         id: 'erWdqEWPm',
         startDttm: 1559238516395,
         sqlEditorId: defaultQueryEditor.id,
-        sql: 'select * from table4',
       },
     },
   },
-};
-
-test('should render offline when the state is offline', async () => {
-  const { getByText } = render(<SouthPane {...mockedEmptyProps} />, {
+});
+const setup = (props: SouthPaneProps, store: Store) =>
+  render(<SouthPane {...props} />, {
     useRedux: true,
-    initialState: {
-      ...initialState,
-      sqlLab: {
-        ...initialState.sqlLab,
-        offline: true,
-      },
-    },
+    ...(store && { store }),
   });
 
-  expect(getByText(STATUS_OPTIONS.offline)).toBeVisible();
-});
+describe('SouthPane', () => {
+  const renderAndWait = (props: SouthPaneProps, store: Store) =>
+    waitFor(async () => setup(props, store));
 
-test('should render tabs for table preview queries', () => {
-  const { getAllByRole } = render(<SouthPane {...mockedProps} />, {
-    useRedux: true,
-    initialState: mockState,
+  it('Renders an empty state for results', async () => {
+    await renderAndWait(mockedEmptyProps, store);
+    const emptyStateText = screen.getByText(/run a query to display results/i);
+    expect(emptyStateText).toBeVisible();
   });
 
-  const tabs = getAllByRole('tab');
-  expect(tabs).toHaveLength(mockState.sqlLab.tables.length + 2);
-  expect(tabs[0]).toHaveTextContent('Results');
-  expect(tabs[1]).toHaveTextContent('Query history');
-  mockState.sqlLab.tables.forEach(({ name }, index) => {
-    expect(tabs[index + 2]).toHaveTextContent(`Preview: \`${name}\``);
+  it('should render offline when the state is offline', async () => {
+    await renderAndWait(
+      mockedEmptyProps,
+      mockStore({
+        ...initialState,
+        sqlLab: {
+          ...initialState.sqlLab,
+          offline: true,
+        },
+      }),
+    );
+
+    expect(screen.getByText(STATUS_OPTIONS.offline)).toBeVisible();
+  });
+
+  it('should pass latest query down to ResultSet component', async () => {
+    await renderAndWait(mockedProps, store);
+
+    expect(screen.getByText(latestQueryProgressMsg)).toBeVisible();
   });
 });
diff --git a/superset-frontend/src/SqlLab/components/SouthPane/index.tsx b/superset-frontend/src/SqlLab/components/SouthPane/index.tsx
index 0bbce99b1c..38a20f9f6d 100644
--- a/superset-frontend/src/SqlLab/components/SouthPane/index.tsx
+++ b/superset-frontend/src/SqlLab/components/SouthPane/index.tsx
@@ -19,8 +19,10 @@
 import React, { createRef, useMemo } from 'react';
 import { shallowEqual, useDispatch, useSelector } from 'react-redux';
 import shortid from 'shortid';
+import Alert from 'src/components/Alert';
 import Tabs from 'src/components/Tabs';
-import { styled, t } from '@superset-ui/core';
+import { EmptyStateMedium } from 'src/components/EmptyState';
+import { FeatureFlag, styled, t, isFeatureEnabled } from '@superset-ui/core';
 
 import { setActiveSouthPaneTab } from 'src/SqlLab/actions/sqlLab';
 
@@ -31,11 +33,11 @@ import ResultSet from '../ResultSet';
 import {
   STATUS_OPTIONS,
   STATE_TYPE_MAP,
+  LOCALSTORAGE_MAX_QUERY_AGE_MS,
   STATUS_OPTIONS_LOCALIZED,
 } from '../../constants';
-import Results from './Results';
 
-const TAB_HEIGHT = 130;
+const TAB_HEIGHT = 140;
 
 /*
     editorQueries are queries executed by users passed from SqlEditor component
@@ -83,6 +85,18 @@ const StyledPane = styled.div<StyledPaneProps>`
   }
 `;
 
+const EXTRA_HEIGHT_RESULTS = 24; // we need extra height in RESULTS tab. because the height from props was calculated based on PREVIEW tab.
+const StyledEmptyStateWrapper = styled.div`
+  height: 100%;
+  .ant-empty-image img {
+    margin-right: 28px;
+  }
+
+  p {
+    margin-right: 28px;
+  }
+`;
+
 const SouthPane = ({
   queryEditorId,
   latestQueryId,
@@ -91,43 +105,128 @@ const SouthPane = ({
   defaultQueryLimit,
 }: SouthPaneProps) => {
   const dispatch = useDispatch();
-  const { offline, tables } = useSelector(
-    ({ sqlLab: { offline, tables } }: SqlLabRootState) => ({
+  const user = useSelector(({ user }: SqlLabRootState) => user, shallowEqual);
+  const { databases, offline, queries, tables } = useSelector(
+    ({ sqlLab: { databases, offline, queries, tables } }: SqlLabRootState) => ({
+      databases,
       offline,
+      queries,
       tables,
     }),
     shallowEqual,
   );
-  const queries = useSelector(
-    ({ sqlLab: { queries } }: SqlLabRootState) => Object.keys(queries),
-    shallowEqual,
+  const editorQueries = useMemo(
+    () =>
+      Object.values(queries).filter(
+        ({ sqlEditorId }) => sqlEditorId === queryEditorId,
+      ),
+    [queries, queryEditorId],
   );
+  const dataPreviewQueries = useMemo(
+    () =>
+      tables
+        .filter(
+          ({ dataPreviewQueryId, queryEditorId: qeId }) =>
+            dataPreviewQueryId &&
+            queryEditorId === qeId &&
+            queries[dataPreviewQueryId],
+        )
+        .map(({ name, dataPreviewQueryId }) => ({
+          ...queries[dataPreviewQueryId || ''],
+          tableName: name,
+        })),
+    [queries, queryEditorId, tables],
+  );
+  const latestQuery = useMemo(
+    () => editorQueries.find(({ id }) => id === latestQueryId),
+    [editorQueries, latestQueryId],
+  );
+
   const activeSouthPaneTab =
     useSelector<SqlLabRootState, string>(
       state => state.sqlLab.activeSouthPaneTab as string,
     ) ?? 'Results';
-
-  const querySet = useMemo(() => new Set(queries), [queries]);
-  const dataPreviewQueries = useMemo(
-    () =>
-      tables.filter(
-        ({ dataPreviewQueryId, queryEditorId: qeId }) =>
-          dataPreviewQueryId &&
-          queryEditorId === qeId &&
-          querySet.has(dataPreviewQueryId),
-      ),
-    [queryEditorId, tables, querySet],
-  );
   const innerTabContentHeight = height - TAB_HEIGHT;
   const southPaneRef = createRef<HTMLDivElement>();
   const switchTab = (id: string) => {
     dispatch(setActiveSouthPaneTab(id));
   };
-
-  return offline ? (
+  const renderOfflineStatus = () => (
     <Label className="m-r-3" type={STATE_TYPE_MAP[STATUS_OPTIONS.offline]}>
       {STATUS_OPTIONS_LOCALIZED.offline}
     </Label>
+  );
+
+  const renderResults = () => {
+    let results;
+    if (latestQuery) {
+      if (latestQuery?.extra?.errors) {
+        latestQuery.errors = latestQuery.extra.errors;
+      }
+      if (
+        isFeatureEnabled(FeatureFlag.SQLLAB_BACKEND_PERSISTENCE) &&
+        latestQuery.state === 'success' &&
+        !latestQuery.resultsKey &&
+        !latestQuery.results
+      ) {
+        results = (
+          <Alert
+            type="warning"
+            message={t(
+              'No stored results found, you need to re-run your query',
+            )}
+          />
+        );
+        return results;
+      }
+      if (Date.now() - latestQuery.startDttm <= LOCALSTORAGE_MAX_QUERY_AGE_MS) {
+        results = (
+          <ResultSet
+            search
+            query={latestQuery}
+            user={user}
+            height={innerTabContentHeight + EXTRA_HEIGHT_RESULTS}
+            database={databases[latestQuery.dbId]}
+            displayLimit={displayLimit}
+            defaultQueryLimit={defaultQueryLimit}
+            showSql
+            showSqlInline
+          />
+        );
+      }
+    } else {
+      results = (
+        <StyledEmptyStateWrapper>
+          <EmptyStateMedium
+            title={t('Run a query to display results')}
+            image="document.svg"
+          />
+        </StyledEmptyStateWrapper>
+      );
+    }
+    return results;
+  };
+
+  const renderDataPreviewTabs = () =>
+    dataPreviewQueries.map(query => (
+      <Tabs.TabPane
+        tab={t('Preview: `%s`', decodeURIComponent(query.tableName))}
+        key={query.id}
+      >
+        <ResultSet
+          query={query}
+          visualize={false}
+          csv={false}
+          cache
+          user={user}
+          height={innerTabContentHeight}
+          displayLimit={displayLimit}
+          defaultQueryLimit={defaultQueryLimit}
+        />
+      </Tabs.TabPane>
+    ));
+  return offline ? (
+    renderOfflineStatus()
   ) : (
     <StyledPane
       data-test="south-pane"
@@ -144,41 +243,16 @@ const SouthPane = ({
         animated={false}
       >
         <Tabs.TabPane tab={t('Results')} key="Results">
-          {latestQueryId && (
-            <Results
-              height={innerTabContentHeight}
-              latestQueryId={latestQueryId}
-              displayLimit={displayLimit}
-              defaultQueryLimit={defaultQueryLimit}
-            />
-          )}
+          {renderResults()}
         </Tabs.TabPane>
         <Tabs.TabPane tab={t('Query history')} key="History">
           <QueryHistory
-            queryEditorId={queryEditorId}
+            queries={editorQueries}
             displayLimit={displayLimit}
             latestQueryId={latestQueryId}
           />
         </Tabs.TabPane>
-        {dataPreviewQueries.map(
-          ({ name, dataPreviewQueryId }) =>
-            dataPreviewQueryId && (
-              <Tabs.TabPane
-                tab={t('Preview: `%s`', decodeURIComponent(name))}
-                key={dataPreviewQueryId}
-              >
-                <ResultSet
-                  queryId={dataPreviewQueryId}
-                  visualize={false}
-                  csv={false}
-                  cache
-                  height={innerTabContentHeight}
-                  displayLimit={displayLimit}
-                  defaultQueryLimit={defaultQueryLimit}
-                />
-              </Tabs.TabPane>
-            ),
-        )}
+        {renderDataPreviewTabs()}
       </Tabs>
     </StyledPane>
   );
diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
index 6a25492ce5..63f67170d0 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditor/SqlEditor.test.tsx
@@ -145,8 +145,8 @@ describe('SqlEditor', () => {
     (SqlEditorLeftBar as jest.Mock).mockImplementation(() => (
       <div data-test="mock-sql-editor-left-bar" />
     ));
-    (ResultSet as unknown as jest.Mock).mockClear();
-    (ResultSet as unknown as jest.Mock).mockImplementation(() => (
+    (ResultSet as jest.Mock).mockClear();
+    (ResultSet as jest.Mock).mockImplementation(() => (
       <div data-test="mock-result-set" />
     ));
   });
@@ -182,8 +182,7 @@ describe('SqlEditor', () => {
     const editor = await findByTestId('react-ace');
     const sql = 'select *';
     const renderCount = (SqlEditorLeftBar as jest.Mock).mock.calls.length;
-    const renderCountForSouthPane = (ResultSet as unknown as jest.Mock).mock
-      .calls.length;
+    const renderCountForSouthPane = (ResultSet as jest.Mock).mock.calls.length;
     expect(SqlEditorLeftBar).toHaveBeenCalledTimes(renderCount);
     expect(ResultSet).toHaveBeenCalledTimes(renderCountForSouthPane);
     fireEvent.change(editor, { target: { value: sql } });
diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.js b/superset-frontend/src/SqlLab/reducers/sqlLab.js
index ce9eed9b9d..59bd0558a1 100644
--- a/superset-frontend/src/SqlLab/reducers/sqlLab.js
+++ b/superset-frontend/src/SqlLab/reducers/sqlLab.js
@@ -345,7 +345,7 @@ export default function sqlLabReducer(state = {}, action) {
         return state;
       }
       const alts = {
-        endDttm: action?.results?.query?.endDttm || now(),
+        endDttm: now(),
         progress: 100,
         results: action.results,
         rows: action?.results?.query?.rows || 0,
@@ -674,14 +674,7 @@ export default function sqlLabReducer(state = {}, action) {
       if (!change) {
         newQueries = state.queries;
       }
-      return {
-        ...state,
-        queries: newQueries,
-        queriesLastUpdate:
-          queriesLastUpdate > state.queriesLastUpdate
-            ? queriesLastUpdate
-            : Date.now(),
-      };
+      return { ...state, queries: newQueries, queriesLastUpdate };
     },
     [actions.CLEAR_INACTIVE_QUERIES]() {
       const { queries } = state;
@@ -708,11 +701,7 @@ export default function sqlLabReducer(state = {}, action) {
             },
           ]),
       );
-      return {
-        ...state,
-        queries: cleanedQueries,
-        queriesLastUpdate: Date.now(),
-      };
+      return { ...state, queries: cleanedQueries };
     },
     [actions.SET_USER_OFFLINE]() {
       return { ...state, offline: action.offline };
diff --git a/superset-frontend/src/SqlLab/reducers/sqlLab.test.js b/superset-frontend/src/SqlLab/reducers/sqlLab.test.js
index 5a70f10bb3..e1a234734b 100644
--- a/superset-frontend/src/SqlLab/reducers/sqlLab.test.js
+++ b/superset-frontend/src/SqlLab/reducers/sqlLab.test.js
@@ -20,7 +20,6 @@ import { QueryState } from '@superset-ui/core';
 import sqlLabReducer from 'src/SqlLab/reducers/sqlLab';
 import * as actions from 'src/SqlLab/actions/sqlLab';
 import { table, initialState as mockState } from '../fixtures';
-import { QUERY_UPDATE_FREQ } from '../components/QueryAutoRefresh';
 
 const initialState = mockState.sqlLab;
 
@@ -405,7 +404,6 @@ describe('sqlLabReducer', () => {
       };
     });
     it('updates queries that have already been completed', () => {
-      const current = Date.now();
       newState = sqlLabReducer(
         {
           ...newState,
@@ -420,10 +418,9 @@ describe('sqlLabReducer', () => {
             },
           },
         },
-        actions.clearInactiveQueries(QUERY_UPDATE_FREQ),
+        actions.clearInactiveQueries(Date.now()),
       );
       expect(newState.queries.abcd.state).toBe(QueryState.SUCCESS);
-      expect(newState.queriesLastUpdate).toBeGreaterThanOrEqual(current);
     });
   });
 });