fix: Query history view button in SqlLab (#36540)

This commit is contained in:
Geidō
2025-12-31 15:18:59 +01:00
committed by GitHub
parent 7cd76e4647
commit d4ba44fce2
4 changed files with 214 additions and 50 deletions

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { useMemo, ReactNode } from 'react';
import { useMemo, ReactNode, useState, useRef } from 'react';
import {
Card,
Button,
@@ -27,9 +27,9 @@ import {
TableView,
} from '@superset-ui/core/components';
import ProgressBar from '@superset-ui/core/components/ProgressBar';
import { t, QueryResponse } from '@superset-ui/core';
import { t, QueryResponse, QueryState } from '@superset-ui/core';
import { useTheme } from '@apache-superset/core/ui';
import { useDispatch, useSelector } from 'react-redux';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import {
queryEditorSetSql,
@@ -37,6 +37,7 @@ import {
fetchQueryResults,
clearQueryResults,
removeQuery,
startQuery,
} from 'src/SqlLab/actions/sqlLab';
import { fDuration, extendedDayjs } from '@superset-ui/core/utils/dates';
import { SqlLabRootState } from 'src/SqlLab/types';
@@ -44,7 +45,7 @@ import { UserWithPermissionsAndRoles as User } from 'src/types/bootstrapTypes';
import { makeUrl } from 'src/utils/pathUtils';
import ResultSet from '../ResultSet';
import HighlightedSql from '../HighlightedSql';
import { StaticPosition, StyledTooltip } from './styles';
import { StaticPosition, StyledTooltip, ModalResultSetWrapper } from './styles';
interface QueryTableQuery extends Omit<
QueryResponse,
@@ -82,6 +83,15 @@ const QueryTable = ({
}: QueryTableProps) => {
const theme = useTheme();
const dispatch = useDispatch();
const [selectedQuery, setSelectedQuery] = useState<QueryResponse | null>(
null,
);
const selectedQueryRef = useRef<QueryResponse | null>(null);
const modalRef = useRef<{
close: () => void;
open: (e: React.MouseEvent) => void;
showModal: boolean;
} | null>(null);
const QUERY_HISTORY_TABLE_HEADERS_LOCALIZED = {
state: t('State'),
@@ -116,6 +126,14 @@ const QueryTable = ({
);
const user = useSelector<SqlLabRootState, User>(state => state.user);
const reduxQueries = useSelector<
SqlLabRootState,
Record<string, QueryResponse>
>(state => state.sqlLab?.queries ?? {}, shallowEqual);
const openAsyncResults = (query: QueryResponse, displayLimit: number) => {
dispatch(fetchQueryResults(query, displayLimit));
};
const data = useMemo(() => {
const restoreSql = (query: QueryResponse) => {
@@ -128,10 +146,6 @@ const QueryTable = ({
dispatch(cloneQueryToNewTab(query, true));
};
const openAsyncResults = (query: QueryResponse, displayLimit: number) => {
dispatch(fetchQueryResults(query, displayLimit));
};
const statusAttributes = {
success: {
config: {
@@ -289,26 +303,17 @@ const QueryTable = ({
);
if (q.resultsKey) {
q.results = (
<ModalTrigger
className="ResultsModal"
triggerNode={
<Button buttonSize="xsmall" buttonStyle="secondary">
{t('View')}
</Button>
}
modalTitle={t('Data preview')}
beforeOpen={() => openAsyncResults(query, displayLimit)}
onExit={() => dispatch(clearQueryResults(query))}
modalBody={
<ResultSet
showSql
queryId={query.id}
displayLimit={displayLimit}
defaultQueryLimit={1000}
/>
}
responsive
/>
<Button
buttonSize="xsmall"
buttonStyle="secondary"
onClick={(e: React.MouseEvent) => {
selectedQueryRef.current = query;
setSelectedQuery(query);
modalRef.current?.open(e);
}}
>
{t('View')}
</Button>
);
} else {
q.results = <></>;
@@ -365,6 +370,55 @@ const QueryTable = ({
return (
<div className="QueryTable">
<ModalTrigger
ref={modalRef}
triggerNode={null}
className="ResultsModal"
modalTitle={t('Data preview')}
beforeOpen={() => {
const query = selectedQueryRef.current;
if (query) {
const existingQuery = reduxQueries[query.id];
if (!existingQuery?.sql && query.sql) {
dispatch(startQuery({ ...query, sql: query.sql }, false));
}
openAsyncResults(query, displayLimit);
}
}}
onExit={() => {
const query = selectedQueryRef.current;
if (query) {
dispatch(clearQueryResults(query));
selectedQueryRef.current = null;
setSelectedQuery(null);
}
}}
modalBody={
selectedQuery ? (
<ModalResultSetWrapper>
{(() => {
const height =
reduxQueries[selectedQuery.id]?.state ===
QueryState.Success &&
reduxQueries[selectedQuery.id]?.results
? Math.floor(window.innerHeight * 0.5)
: undefined;
return (
<ResultSet
showSql
queryId={selectedQuery.id}
displayLimit={displayLimit}
defaultQueryLimit={1000}
useFixedHeight
height={height}
/>
);
})()}
</ModalResultSetWrapper>
) : null
}
responsive
/>
<TableView
columns={columnsOfTable}
data={data}