mirror of https://github.com/apache/superset.git
chore: Remove actions prop and refactor code in SQL Lab (#22231)
This commit is contained in:
parent
b2d909f529
commit
f3bf3ec2ed
|
@ -296,6 +296,7 @@ export type Query = {
|
|||
errorMessage: string | null;
|
||||
extra: {
|
||||
progress: string | null;
|
||||
errors?: SupersetError[];
|
||||
};
|
||||
id: string;
|
||||
isDataPreview: boolean;
|
||||
|
|
|
@ -20,16 +20,8 @@ import React from 'react';
|
|||
import { render, screen } from 'spec/helpers/testing-library';
|
||||
import QueryHistory from 'src/SqlLab/components/QueryHistory';
|
||||
|
||||
const NOOP = () => {};
|
||||
const mockedProps = {
|
||||
queries: [],
|
||||
actions: {
|
||||
queryEditorSetAndSaveSql: NOOP,
|
||||
cloneQueryToNewTab: NOOP,
|
||||
fetchQueryResults: NOOP,
|
||||
clearQueryResults: NOOP,
|
||||
removeQuery: NOOP,
|
||||
},
|
||||
displayLimit: 1000,
|
||||
latestQueryId: 'yhMUZCGb',
|
||||
};
|
||||
|
|
|
@ -23,13 +23,6 @@ import QueryTable from 'src/SqlLab/components/QueryTable';
|
|||
|
||||
interface QueryHistoryProps {
|
||||
queries: QueryResponse[];
|
||||
actions: {
|
||||
queryEditorSetAndSaveSql: Function;
|
||||
cloneQueryToNewTab: Function;
|
||||
fetchQueryResults: Function;
|
||||
clearQueryResults: Function;
|
||||
removeQuery: Function;
|
||||
};
|
||||
displayLimit: number;
|
||||
latestQueryId: string | undefined;
|
||||
}
|
||||
|
@ -47,7 +40,6 @@ const StyledEmptyStateWrapper = styled.div`
|
|||
|
||||
const QueryHistory = ({
|
||||
queries,
|
||||
actions,
|
||||
displayLimit,
|
||||
latestQueryId,
|
||||
}: QueryHistoryProps) =>
|
||||
|
@ -64,7 +56,6 @@ const QueryHistory = ({
|
|||
'actions',
|
||||
]}
|
||||
queries={queries}
|
||||
actions={actions}
|
||||
displayLimit={displayLimit}
|
||||
latestQueryId={latestQueryId}
|
||||
/>
|
||||
|
|
|
@ -43,7 +43,6 @@ fetchMock.get(DATABASE_ENDPOINT, []);
|
|||
|
||||
describe('QuerySearch', () => {
|
||||
const mockedProps = {
|
||||
actions: { addDangerToast: jest.fn() },
|
||||
displayLimit: 50,
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { setDatabases, addDangerToast } from 'src/SqlLab/actions/sqlLab';
|
||||
import Button from 'src/components/Button';
|
||||
import Select from 'src/components/DeprecatedSelect';
|
||||
import { styled, t, SupersetClient, QueryResponse } from '@superset-ui/core';
|
||||
|
@ -33,15 +36,6 @@ import { STATUS_OPTIONS, TIME_OPTIONS } from 'src/SqlLab/constants';
|
|||
import QueryTable from '../QueryTable';
|
||||
|
||||
interface QuerySearchProps {
|
||||
actions: {
|
||||
addDangerToast: (msg: string) => void;
|
||||
setDatabases: (data: Record<string, any>) => Record<string, any>;
|
||||
queryEditorSetAndSaveSql: Function;
|
||||
cloneQueryToNewTab: Function;
|
||||
fetchQueryResults: Function;
|
||||
clearQueryResults: Function;
|
||||
removeQuery: Function;
|
||||
};
|
||||
displayLimit: number;
|
||||
}
|
||||
|
||||
|
@ -77,7 +71,10 @@ const TableStyles = styled.div`
|
|||
const StyledTableStylesContainer = styled.div`
|
||||
overflow: auto;
|
||||
`;
|
||||
function QuerySearch({ actions, displayLimit }: QuerySearchProps) {
|
||||
|
||||
const QuerySearch = ({ displayLimit }: QuerySearchProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [databaseId, setDatabaseId] = useState<string>('');
|
||||
const [userId, setUserId] = useState<string>('');
|
||||
const [searchText, setSearchText] = useState<string>('');
|
||||
|
@ -133,7 +130,7 @@ function QuerySearch({ actions, displayLimit }: QuerySearchProps) {
|
|||
const queries = Object.values(response.json);
|
||||
setQueriesArray(queries);
|
||||
} catch (err) {
|
||||
actions.addDangerToast(t('An error occurred when refreshing queries'));
|
||||
dispatch(addDangerToast(t('An error occurred when refreshing queries')));
|
||||
} finally {
|
||||
setQueriesLoading(false);
|
||||
}
|
||||
|
@ -178,10 +175,10 @@ function QuerySearch({ actions, displayLimit }: QuerySearchProps) {
|
|||
value: id,
|
||||
label: database_name,
|
||||
}));
|
||||
actions.setDatabases(result);
|
||||
dispatch(setDatabases(result));
|
||||
if (result.length === 0) {
|
||||
actions.addDangerToast(
|
||||
t("It seems you don't have access to any database"),
|
||||
dispatch(
|
||||
addDangerToast(t("It seems you don't have access to any database")),
|
||||
);
|
||||
}
|
||||
return options;
|
||||
|
@ -280,7 +277,6 @@ function QuerySearch({ actions, displayLimit }: QuerySearchProps) {
|
|||
onUserClicked={onUserClicked}
|
||||
onDbClicked={onDbClicked}
|
||||
queries={queriesArray}
|
||||
actions={actions}
|
||||
displayLimit={displayLimit}
|
||||
/>
|
||||
</TableStyles>
|
||||
|
@ -288,5 +284,6 @@ function QuerySearch({ actions, displayLimit }: QuerySearchProps) {
|
|||
</StyledTableStylesContainer>
|
||||
</TableWrapper>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default QuerySearch;
|
||||
|
|
|
@ -25,13 +25,11 @@ import TableView from 'src/components/TableView';
|
|||
import TableCollection from 'src/components/TableCollection';
|
||||
import { Provider } from 'react-redux';
|
||||
import { queries, user } from 'src/SqlLab/fixtures';
|
||||
import * as actions from 'src/SqlLab/actions/sqlLab';
|
||||
|
||||
describe('QueryTable', () => {
|
||||
const mockedProps = {
|
||||
queries,
|
||||
displayLimit: 100,
|
||||
actions,
|
||||
latestQueryId: 'ryhMUZCGb',
|
||||
};
|
||||
it('is valid', () => {
|
||||
|
|
|
@ -22,7 +22,15 @@ import Card from 'src/components/Card';
|
|||
import ProgressBar from 'src/components/ProgressBar';
|
||||
import Label from 'src/components/Label';
|
||||
import { t, useTheme, QueryResponse } from '@superset-ui/core';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import {
|
||||
queryEditorSetAndSaveSql,
|
||||
cloneQueryToNewTab,
|
||||
fetchQueryResults,
|
||||
clearQueryResults,
|
||||
removeQuery,
|
||||
} from 'src/SqlLab/actions/sqlLab';
|
||||
import TableView from 'src/components/TableView';
|
||||
import Button from 'src/components/Button';
|
||||
import { fDuration } from 'src/utils/dates';
|
||||
|
@ -45,13 +53,6 @@ interface QueryTableQuery
|
|||
|
||||
interface QueryTableProps {
|
||||
columns?: string[];
|
||||
actions: {
|
||||
queryEditorSetAndSaveSql: Function;
|
||||
cloneQueryToNewTab: Function;
|
||||
fetchQueryResults: Function;
|
||||
clearQueryResults: Function;
|
||||
removeQuery: Function;
|
||||
};
|
||||
queries?: QueryResponse[];
|
||||
onUserClicked?: Function;
|
||||
onDbClicked?: Function;
|
||||
|
@ -66,7 +67,6 @@ const openQuery = (id: number) => {
|
|||
|
||||
const QueryTable = ({
|
||||
columns = ['started', 'duration', 'rows'],
|
||||
actions,
|
||||
queries = [],
|
||||
onUserClicked = () => undefined,
|
||||
onDbClicked = () => undefined,
|
||||
|
@ -74,6 +74,7 @@ const QueryTable = ({
|
|||
latestQueryId,
|
||||
}: QueryTableProps) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const setHeaders = (column: string) => {
|
||||
if (column === 'sql') {
|
||||
|
@ -93,25 +94,17 @@ const QueryTable = ({
|
|||
|
||||
const user = useSelector<SqlLabRootState, User>(state => state.sqlLab.user);
|
||||
|
||||
const {
|
||||
queryEditorSetAndSaveSql,
|
||||
cloneQueryToNewTab,
|
||||
fetchQueryResults,
|
||||
clearQueryResults,
|
||||
removeQuery,
|
||||
} = actions;
|
||||
|
||||
const data = useMemo(() => {
|
||||
const restoreSql = (query: QueryResponse) => {
|
||||
queryEditorSetAndSaveSql({ id: query.sqlEditorId }, query.sql);
|
||||
dispatch(queryEditorSetAndSaveSql({ id: query.sqlEditorId }, query.sql));
|
||||
};
|
||||
|
||||
const openQueryInNewTab = (query: QueryResponse) => {
|
||||
cloneQueryToNewTab(query, true);
|
||||
dispatch(cloneQueryToNewTab(query, true));
|
||||
};
|
||||
|
||||
const openAsyncResults = (query: QueryResponse, displayLimit: number) => {
|
||||
fetchQueryResults(query, displayLimit);
|
||||
dispatch(fetchQueryResults(query, displayLimit));
|
||||
};
|
||||
|
||||
const statusAttributes = {
|
||||
|
@ -239,7 +232,7 @@ const QueryTable = ({
|
|||
}
|
||||
modalTitle={t('Data preview')}
|
||||
beforeOpen={() => openAsyncResults(query, displayLimit)}
|
||||
onExit={() => clearQueryResults(query)}
|
||||
onExit={() => dispatch(clearQueryResults(query))}
|
||||
modalBody={
|
||||
<ResultSet
|
||||
showSql
|
||||
|
@ -293,7 +286,7 @@ const QueryTable = ({
|
|||
{q.id !== latestQueryId && (
|
||||
<StyledTooltip
|
||||
tooltip={t('Remove query from log')}
|
||||
onClick={() => removeQuery(query)}
|
||||
onClick={() => dispatch(removeQuery(query))}
|
||||
>
|
||||
<Icons.Trash iconSize="xl" />
|
||||
</StyledTooltip>
|
||||
|
@ -303,19 +296,7 @@ const QueryTable = ({
|
|||
return q;
|
||||
})
|
||||
.reverse();
|
||||
}, [
|
||||
queries,
|
||||
onUserClicked,
|
||||
onDbClicked,
|
||||
user,
|
||||
displayLimit,
|
||||
actions,
|
||||
clearQueryResults,
|
||||
cloneQueryToNewTab,
|
||||
fetchQueryResults,
|
||||
queryEditorSetAndSaveSql,
|
||||
removeQuery,
|
||||
]);
|
||||
}, [queries, onUserClicked, onDbClicked, user, displayLimit]);
|
||||
|
||||
return (
|
||||
<div className="QueryTable">
|
||||
|
|
|
@ -23,15 +23,15 @@ import { DropdownButton } from 'src/components/DropdownButton';
|
|||
import Button from 'src/components/Button';
|
||||
import { DropdownButtonProps } from 'antd/lib/dropdown';
|
||||
|
||||
interface Props {
|
||||
interface SaveDatasetActionButtonProps {
|
||||
setShowSave: (arg0: boolean) => void;
|
||||
overlayMenu: JSX.Element | null;
|
||||
}
|
||||
|
||||
export default function SaveDatasetActionButton({
|
||||
const SaveDatasetActionButton = ({
|
||||
setShowSave,
|
||||
overlayMenu,
|
||||
}: Props) {
|
||||
}: SaveDatasetActionButtonProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const StyledDropdownButton = styled(
|
||||
|
@ -80,4 +80,6 @@ export default function SaveDatasetActionButton({
|
|||
{t('Save')}
|
||||
</StyledDropdownButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SaveDatasetActionButton;
|
||||
|
|
|
@ -19,47 +19,30 @@
|
|||
import React from 'react';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import { styledShallow as shallow } from 'spec/helpers/theming';
|
||||
import { render, screen, act } from 'spec/helpers/testing-library';
|
||||
import SouthPaneContainer from 'src/SqlLab/components/SouthPane/state';
|
||||
import ResultSet from 'src/SqlLab/components/ResultSet';
|
||||
import { render, screen, waitFor } from 'spec/helpers/testing-library';
|
||||
import SouthPane 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 { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||
|
||||
const NOOP = () => {};
|
||||
|
||||
const mockedProps = {
|
||||
queryEditorId: defaultQueryEditor.id,
|
||||
latestQueryId: 'LCly_kkIN',
|
||||
actions: {},
|
||||
activeSouthPaneTab: '',
|
||||
height: 1,
|
||||
displayLimit: 1,
|
||||
databases: {},
|
||||
defaultQueryLimit: 100,
|
||||
};
|
||||
|
||||
const mockedEmptyProps = {
|
||||
queryEditorId: 'random_id',
|
||||
latestQueryId: '',
|
||||
actions: {
|
||||
queryEditorSetAndSaveSql: NOOP,
|
||||
cloneQueryToNewTab: NOOP,
|
||||
fetchQueryResults: NOOP,
|
||||
clearQueryResults: NOOP,
|
||||
removeQuery: NOOP,
|
||||
setActiveSouthPaneTab: NOOP,
|
||||
},
|
||||
activeSouthPaneTab: '',
|
||||
height: 100,
|
||||
databases: '',
|
||||
displayLimit: 100,
|
||||
user: UserWithPermissionsAndRoles,
|
||||
defaultQueryLimit: 100,
|
||||
};
|
||||
|
||||
const latestQueryProgressMsg = 'LATEST QUERY MESSAGE - LCly_kkIN';
|
||||
|
||||
const middlewares = [thunk];
|
||||
const mockStore = configureStore(middlewares);
|
||||
const store = mockStore({
|
||||
|
@ -84,6 +67,7 @@ const store = mockStore({
|
|||
id: 'LCly_kkIN',
|
||||
startDttm: Date.now(),
|
||||
sqlEditorId: defaultQueryEditor.id,
|
||||
extra: { progress: latestQueryProgressMsg },
|
||||
},
|
||||
lXJa7F9_r: {
|
||||
cached: false,
|
||||
|
@ -115,48 +99,40 @@ const store = mockStore({
|
|||
},
|
||||
},
|
||||
});
|
||||
const setup = (overrides = {}) => (
|
||||
<SouthPaneContainer store={store} {...mockedProps} {...overrides} />
|
||||
);
|
||||
|
||||
describe('SouthPane - Enzyme', () => {
|
||||
const getWrapper = () => shallow(setup()).dive();
|
||||
|
||||
let wrapper;
|
||||
|
||||
it('should render offline when the state is offline', () => {
|
||||
wrapper = getWrapper().dive();
|
||||
wrapper.setProps({ offline: true });
|
||||
expect(wrapper.childAt(0).text()).toBe(STATUS_OPTIONS.offline);
|
||||
const setup = (props, store) =>
|
||||
render(<SouthPane {...props} />, {
|
||||
useRedux: true,
|
||||
...(store && { store }),
|
||||
});
|
||||
|
||||
it('should pass latest query down to ResultSet component', () => {
|
||||
wrapper = getWrapper().dive();
|
||||
expect(wrapper.find(ResultSet)).toExist();
|
||||
// for editorQueries
|
||||
expect(wrapper.find(ResultSet).first().props().query.id).toEqual(
|
||||
mockedProps.latestQueryId,
|
||||
);
|
||||
// for dataPreviewQueries
|
||||
expect(wrapper.find(ResultSet).last().props().query.id).toEqual(
|
||||
'2g2_iRFMl',
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('SouthPane', () => {
|
||||
const renderAndWait = (props, store) =>
|
||||
waitFor(async () => setup(props, store));
|
||||
|
||||
describe('SouthPane - RTL', () => {
|
||||
const renderAndWait = overrides => {
|
||||
const mounted = act(async () => {
|
||||
render(setup(overrides));
|
||||
});
|
||||
|
||||
return mounted;
|
||||
};
|
||||
it('Renders an empty state for results', async () => {
|
||||
await renderAndWait(mockedEmptyProps);
|
||||
|
||||
await renderAndWait(mockedEmptyProps, store);
|
||||
const emptyStateText = screen.getByText(/run a query to display results/i);
|
||||
|
||||
expect(emptyStateText).toBeVisible();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,16 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { createRef } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import shortid from 'shortid';
|
||||
import Alert from 'src/components/Alert';
|
||||
import Tabs from 'src/components/Tabs';
|
||||
import { EmptyStateMedium } from 'src/components/EmptyState';
|
||||
import { t, styled } from '@superset-ui/core';
|
||||
|
||||
import { setActiveSouthPaneTab } from 'src/SqlLab/actions/sqlLab';
|
||||
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
|
||||
|
||||
import Label from 'src/components/Label';
|
||||
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||
import { SqlLabRootState } from 'src/SqlLab/types';
|
||||
import QueryHistory from '../QueryHistory';
|
||||
import ResultSet from '../ResultSet';
|
||||
import {
|
||||
|
@ -39,27 +41,13 @@ const TAB_HEIGHT = 140;
|
|||
|
||||
/*
|
||||
editorQueries are queries executed by users passed from SqlEditor component
|
||||
dataPrebiewQueries are all queries executed for preview of table data (from SqlEditorLeft)
|
||||
dataPreviewQueries are all queries executed for preview of table data (from SqlEditorLeft)
|
||||
*/
|
||||
export interface SouthPanePropTypes {
|
||||
export interface SouthPaneProps {
|
||||
queryEditorId: string;
|
||||
editorQueries: any[];
|
||||
latestQueryId?: string;
|
||||
dataPreviewQueries: any[];
|
||||
actions: {
|
||||
queryEditorSetAndSaveSql: Function;
|
||||
cloneQueryToNewTab: Function;
|
||||
fetchQueryResults: Function;
|
||||
clearQueryResults: Function;
|
||||
removeQuery: Function;
|
||||
setActiveSouthPaneTab: Function;
|
||||
};
|
||||
activeSouthPaneTab?: string;
|
||||
height: number;
|
||||
databases: Record<string, any>;
|
||||
offline?: boolean;
|
||||
displayLimit: number;
|
||||
user: UserWithPermissionsAndRoles;
|
||||
defaultQueryLimit: number;
|
||||
}
|
||||
|
||||
|
@ -111,23 +99,49 @@ const StyledEmptyStateWrapper = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export default function SouthPane({
|
||||
editorQueries,
|
||||
const SouthPane = ({
|
||||
queryEditorId,
|
||||
latestQueryId,
|
||||
dataPreviewQueries,
|
||||
actions,
|
||||
activeSouthPaneTab = 'Results',
|
||||
height,
|
||||
databases,
|
||||
offline = false,
|
||||
displayLimit,
|
||||
user,
|
||||
defaultQueryLimit,
|
||||
}: SouthPanePropTypes) {
|
||||
}: SouthPaneProps) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { editorQueries, dataPreviewQueries, databases, offline, user } =
|
||||
useSelector(({ sqlLab }: SqlLabRootState) => {
|
||||
const { databases, offline, user, queries, tables } = sqlLab;
|
||||
const dataPreviewQueries = tables
|
||||
.filter(
|
||||
({ dataPreviewQueryId, queryEditorId: qeId }) =>
|
||||
dataPreviewQueryId &&
|
||||
queryEditorId === qeId &&
|
||||
queries[dataPreviewQueryId],
|
||||
)
|
||||
.map(({ name, dataPreviewQueryId }) => ({
|
||||
...queries[dataPreviewQueryId],
|
||||
tableName: name,
|
||||
}));
|
||||
const editorQueries = Object.values(queries).filter(
|
||||
({ sqlEditorId }) => sqlEditorId === queryEditorId,
|
||||
);
|
||||
return {
|
||||
editorQueries,
|
||||
dataPreviewQueries,
|
||||
databases,
|
||||
offline: offline ?? false,
|
||||
user,
|
||||
};
|
||||
});
|
||||
|
||||
const activeSouthPaneTab =
|
||||
useSelector<SqlLabRootState, string>(
|
||||
state => state.sqlLab.activeSouthPaneTab as string,
|
||||
) ?? 'Results';
|
||||
const innerTabContentHeight = height - TAB_HEIGHT;
|
||||
const southPaneRef = createRef<HTMLDivElement>();
|
||||
const switchTab = (id: string) => {
|
||||
actions.setActiveSouthPaneTab(id);
|
||||
dispatch(setActiveSouthPaneTab(id));
|
||||
};
|
||||
const renderOfflineStatus = () => (
|
||||
<Label className="m-r-3" type={STATE_TYPE_MAP[STATUS_OPTIONS.offline]}>
|
||||
|
@ -209,7 +223,12 @@ export default function SouthPane({
|
|||
return offline ? (
|
||||
renderOfflineStatus()
|
||||
) : (
|
||||
<StyledPane className="SouthPane" height={height} ref={southPaneRef}>
|
||||
<StyledPane
|
||||
data-test="south-pane"
|
||||
className="SouthPane"
|
||||
height={height}
|
||||
ref={southPaneRef}
|
||||
>
|
||||
<Tabs
|
||||
activeKey={activeSouthPaneTab}
|
||||
className="SouthPaneTabs"
|
||||
|
@ -224,7 +243,6 @@ export default function SouthPane({
|
|||
<Tabs.TabPane tab={t('Query history')} key="History">
|
||||
<QueryHistory
|
||||
queries={editorQueries}
|
||||
actions={actions}
|
||||
displayLimit={displayLimit}
|
||||
latestQueryId={latestQueryId}
|
||||
/>
|
||||
|
@ -233,4 +251,6 @@ export default function SouthPane({
|
|||
</Tabs>
|
||||
</StyledPane>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SouthPane;
|
||||
|
|
|
@ -1,61 +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 { connect } from 'react-redux';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import * as Actions from 'src/SqlLab/actions/sqlLab';
|
||||
import { SqlLabRootState } from 'src/SqlLab/types';
|
||||
import SouthPane, { SouthPanePropTypes } from '.';
|
||||
|
||||
function mapStateToProps(
|
||||
{ sqlLab }: SqlLabRootState,
|
||||
{ queryEditorId }: SouthPanePropTypes,
|
||||
) {
|
||||
const { databases, activeSouthPaneTab, offline, user, queries, tables } =
|
||||
sqlLab;
|
||||
const dataPreviewQueries = tables
|
||||
.filter(
|
||||
({ dataPreviewQueryId, queryEditorId: qeId }) =>
|
||||
dataPreviewQueryId &&
|
||||
queryEditorId === qeId &&
|
||||
queries[dataPreviewQueryId],
|
||||
)
|
||||
.map(({ name, dataPreviewQueryId }) => ({
|
||||
...queries[dataPreviewQueryId],
|
||||
tableName: name,
|
||||
}));
|
||||
const editorQueries = Object.values(queries).filter(
|
||||
({ sqlEditorId }) => sqlEditorId === queryEditorId,
|
||||
);
|
||||
return {
|
||||
editorQueries,
|
||||
dataPreviewQueries,
|
||||
activeSouthPaneTab,
|
||||
databases,
|
||||
offline,
|
||||
user,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch: Dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators<any, any>(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect<any>(mapStateToProps, mapDispatchToProps)(SouthPane);
|
|
@ -30,14 +30,9 @@ import {
|
|||
SQL_TOOLBAR_HEIGHT,
|
||||
} from 'src/SqlLab/constants';
|
||||
import AceEditorWrapper from 'src/SqlLab/components/AceEditorWrapper';
|
||||
import ConnectedSouthPane from 'src/SqlLab/components/SouthPane/state';
|
||||
import SouthPane from 'src/SqlLab/components/SouthPane';
|
||||
import SqlEditor from 'src/SqlLab/components/SqlEditor';
|
||||
import QueryProvider from 'src/views/QueryProvider';
|
||||
import {
|
||||
queryEditorSetFunctionNames,
|
||||
queryEditorSetSelectedText,
|
||||
queryEditorSetSchemaOptions,
|
||||
} from 'src/SqlLab/actions/sqlLab';
|
||||
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
|
||||
import {
|
||||
initialState,
|
||||
|
@ -97,13 +92,6 @@ const setup = (props = {}, store) =>
|
|||
|
||||
describe('SqlEditor', () => {
|
||||
const mockedProps = {
|
||||
actions: {
|
||||
queryEditorSetFunctionNames,
|
||||
queryEditorSetSelectedText,
|
||||
queryEditorSetSchemaOptions,
|
||||
addDangerToast: jest.fn(),
|
||||
removeDataPreview: jest.fn(),
|
||||
},
|
||||
queryEditor: initialState.sqlLab.queryEditors[0],
|
||||
latestQuery: queries[0],
|
||||
tables: [table],
|
||||
|
@ -238,7 +226,7 @@ describe('SqlEditor', () => {
|
|||
await waitForComponentToPaint(wrapper);
|
||||
const totalSize =
|
||||
parseFloat(wrapper.find(AceEditorWrapper).props().height) +
|
||||
wrapper.find(ConnectedSouthPane).props().height +
|
||||
wrapper.find(SouthPane).props().height +
|
||||
SQL_TOOLBAR_HEIGHT +
|
||||
SQL_EDITOR_GUTTER_MARGIN * 2 +
|
||||
SQL_EDITOR_GUTTER_HEIGHT;
|
||||
|
@ -252,7 +240,7 @@ describe('SqlEditor', () => {
|
|||
await waitForComponentToPaint(wrapper);
|
||||
const totalSize =
|
||||
parseFloat(wrapper.find(AceEditorWrapper).props().height) +
|
||||
wrapper.find(ConnectedSouthPane).props().height +
|
||||
wrapper.find(SouthPane).props().height +
|
||||
SQL_TOOLBAR_HEIGHT +
|
||||
SQL_EDITOR_GUTTER_MARGIN * 2 +
|
||||
SQL_EDITOR_GUTTER_HEIGHT;
|
||||
|
|
|
@ -76,7 +76,7 @@ import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
|||
import { EmptyStateBig } from 'src/components/EmptyState';
|
||||
import { isEmpty } from 'lodash';
|
||||
import TemplateParamsEditor from '../TemplateParamsEditor';
|
||||
import ConnectedSouthPane from '../SouthPane/state';
|
||||
import SouthPane from '../SouthPane';
|
||||
import SaveQuery from '../SaveQuery';
|
||||
import ScheduleQueryButton from '../ScheduleQueryButton';
|
||||
import EstimateQueryCostButton from '../EstimateQueryCostButton';
|
||||
|
@ -135,7 +135,6 @@ const StyledSidebar = styled.div`
|
|||
`;
|
||||
|
||||
const propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
tables: PropTypes.array.isRequired,
|
||||
queryEditor: PropTypes.object.isRequired,
|
||||
defaultQueryLimit: PropTypes.number.isRequired,
|
||||
|
@ -146,7 +145,6 @@ const propTypes = {
|
|||
};
|
||||
|
||||
const SqlEditor = ({
|
||||
actions,
|
||||
tables,
|
||||
queryEditor,
|
||||
defaultQueryLimit,
|
||||
|
@ -617,10 +615,9 @@ const SqlEditor = ({
|
|||
/>
|
||||
{renderEditorBottomBar(hotkeys)}
|
||||
</div>
|
||||
<ConnectedSouthPane
|
||||
<SouthPane
|
||||
queryEditorId={queryEditor.id}
|
||||
latestQueryId={latestQuery?.id}
|
||||
actions={actions}
|
||||
height={southPaneHeight}
|
||||
displayLimit={displayLimit}
|
||||
defaultQueryLimit={defaultQueryLimit}
|
||||
|
|
|
@ -264,7 +264,6 @@ class TabbedSqlEditors extends React.PureComponent {
|
|||
<SqlEditor
|
||||
tables={this.props.tables.filter(xt => xt.queryEditorId === qe.id)}
|
||||
queryEditor={qe}
|
||||
actions={this.props.actions}
|
||||
defaultQueryLimit={this.props.defaultQueryLimit}
|
||||
maxRow={this.props.maxRow}
|
||||
displayLimit={this.props.displayLimit}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { JsonObject, Query, QueryResponse } from '@superset-ui/core';
|
||||
import { JsonObject, QueryResponse } from '@superset-ui/core';
|
||||
import { SupersetError } from 'src/components/ErrorMessage/types';
|
||||
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||
import { ToastType } from 'src/components/MessageToasts/types';
|
||||
|
@ -69,7 +69,7 @@ export type SqlLabRootState = {
|
|||
databases: Record<string, any>;
|
||||
dbConnect: boolean;
|
||||
offline: boolean;
|
||||
queries: Record<string, Query>;
|
||||
queries: Record<string, QueryResponse>;
|
||||
queryEditors: QueryEditor[];
|
||||
tabHistory: string[]; // default is activeTab ? [activeTab.id.toString()] : []
|
||||
tables: Record<string, any>[];
|
||||
|
|
Loading…
Reference in New Issue