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 23:05:05 UTC

(superset) branch master updated: fix: Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)" (#26284)

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

justinpark pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 8450cca998 fix: Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)" (#26284)
8450cca998 is described below

commit 8450cca9989eed29b96f0bf9f963ab07a3ee434e
Author: JUST.in DO IT <ju...@airbnb.com>
AuthorDate: Fri Dec 15 15:05:00 2023 -0800

    fix: Revert "fix(sqllab): flaky json explore modal due to over-rendering (#26156)" (#26284)
---
 .../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);
     });
   });
 });