diff --git a/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx b/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx index 98affc0055..108835ea0c 100644 --- a/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx +++ b/superset-frontend/spec/javascripts/sqllab/ExploreResultsButton_spec.jsx @@ -24,7 +24,6 @@ import sinon from 'sinon'; import fetchMock from 'fetch-mock'; import shortid from 'shortid'; import sqlLabReducer from 'src/SqlLab/reducers/index'; -import * as actions from 'src/SqlLab/actions/sqlLab'; import ExploreResultsButton from 'src/SqlLab/components/ExploreResultsButton'; import * as exploreUtils from 'src/explore/exploreUtils'; import Button from 'src/components/Button'; @@ -184,77 +183,5 @@ describe('ExploreResultsButton', () => { wrapper.instance().buildVizOptions.restore(); fetchMock.reset(); }); - - it('should build request with correct args', () => { - return new Promise(done => { - wrapper.instance().visualize(); - - setTimeout(() => { - const calls = fetchMock.calls(visualizeEndpoint); - expect(calls).toHaveLength(1); - const formData = calls[0][1].body; - Object.keys(mockOptions).forEach(key => { - // eslint-disable-next-line no-unused-expressions - expect(formData.get(key)).toBeDefined(); - }); - - done(); - }); - }); - }); - - it('should export chart and add an info toast', () => { - return new Promise(done => { - const infoToastSpy = sinon.spy(); - const datasourceSpy = sinon.stub(); - - datasourceSpy.callsFake(() => Promise.resolve(visualizationPayload)); - - wrapper.setProps({ - actions: { - addInfoToast: infoToastSpy, - createDatasource: datasourceSpy, - }, - }); - - wrapper.instance().visualize(); - - setTimeout(() => { - expect(datasourceSpy.callCount).toBe(1); - expect(exploreUtils.exploreChart.callCount).toBe(1); - expect(exploreUtils.exploreChart.getCall(0).args[0].datasource).toBe( - '107__table', - ); - expect(infoToastSpy.callCount).toBe(1); - done(); - }); - }); - }); - - it('should add error toast', () => { - return new Promise(done => { - const dangerToastSpy = sinon.stub(actions, 'addDangerToast'); - const datasourceSpy = sinon.stub(); - - datasourceSpy.callsFake(() => Promise.reject({ error: 'error' })); - - wrapper.setProps({ - actions: { - createDatasource: datasourceSpy, - addDangerToast: dangerToastSpy, - }, - }); - - wrapper.instance().visualize(); - - setTimeout(() => { - expect(datasourceSpy.callCount).toBe(1); - expect(exploreUtils.exportChart.callCount).toBe(0); - expect(dangerToastSpy.callCount).toBe(1); - dangerToastSpy.restore(); - done(); - }); - }); - }); }); }); diff --git a/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx b/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx index 4b6ef601ef..0da9a9d07a 100644 --- a/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx +++ b/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx @@ -30,11 +30,16 @@ describe('SaveDatasetModal', () => { userDatasetsOwned: [], handleSaveDatasetRadioBtnState: () => {}, saveDatasetRadioBtnState: 1, - shouldOverwriteDataset: false, handleOverwriteCancel: () => {}, handleOverwriteDataset: () => {}, handleOverwriteDatasetOption: () => {}, defaultCreateDatasetValue: 'someDatasets', + shouldOverwriteDataset: false, + userDatasetOptions: [], + disableSaveAndExploreBtn: false, + handleSaveDatasetModalSearch: () => {}, + filterAutocompleteOption: () => false, + onChangeAutoComplete: () => {}, }; it('renders a radio group btn', () => { const wrapper = shallow(); diff --git a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx index f447b43e43..fc8c8ac017 100644 --- a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx +++ b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx @@ -26,9 +26,7 @@ import { t } from '@superset-ui/core'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import shortid from 'shortid'; -import Modal from 'src/common/components/Modal'; import Button from 'src/components/Button'; -import { exploreChart } from '../../explore/exploreUtils'; import * as actions from '../actions/sqlLab'; const propTypes = { @@ -37,6 +35,7 @@ const propTypes = { errorMessage: PropTypes.string, timeout: PropTypes.number, database: PropTypes.object.isRequired, + onClick: PropTypes.func.isRequired, }; const defaultProps = { query: {}, @@ -45,34 +44,12 @@ const defaultProps = { class ExploreResultsButton extends React.PureComponent { constructor(props) { super(props); - this.visualize = this.visualize.bind(this); - this.onClick = this.onClick.bind(this); this.getInvalidColumns = this.getInvalidColumns.bind(this); this.renderInvalidColumnMessage = this.renderInvalidColumnMessage.bind( this, ); } - onClick() { - const { timeout } = this.props; - const msg = this.renderInvalidColumnMessage(); - if (Math.round(this.getQueryDuration()) > timeout) { - Modal.confirm({ - title: t('Explore'), - content: this.renderTimeoutWarning(), - onOk: this.visualize, - icon: null, - }); - } else if (msg) { - Modal.warning({ - title: t('Explore'), - content: msg, - }); - } else { - this.visualize(); - } - } - getColumns() { const { props } = this; if ( @@ -123,35 +100,6 @@ class ExploreResultsButton extends React.PureComponent { }; } - visualize() { - this.props.actions - .createDatasource(this.buildVizOptions()) - .then(data => { - const columns = this.getColumns(); - const formData = { - datasource: `${data.table_id}__table`, - metrics: [], - groupby: [], - time_range: 'No filter', - viz_type: 'table', - all_columns: columns.map(c => c.name), - row_limit: 1000, - }; - - this.props.actions.addInfoToast( - t('Creating a data source and creating a new tab'), - ); - - // open new window for data visualization - exploreChart(formData); - }) - .catch(() => { - this.props.actions.addDangerToast( - this.props.errorMessage || t('An error occurred'), - ); - }); - } - renderTimeoutWarning() { return ( @@ -203,7 +151,7 @@ class ExploreResultsButton extends React.PureComponent { <> )} {shouldOverwriteDataset && ( <> - )} @@ -155,24 +144,29 @@ export const SaveDatasetModal: FunctionComponent = ({ className="smd-input" defaultValue={defaultCreateDatasetValue} onChange={handleDatasetNameChange} + disabled={saveDatasetRadioBtnState !== 1} /> Overwrite existing )} {shouldOverwriteDataset && ( -
Are you sure you want to overwrite this dataset?
+
+ Are you sure you want to overwrite this dataset? +
)} diff --git a/superset-frontend/src/api/dataset.ts b/superset-frontend/src/api/dataset.ts index 048487c50e..d426daffdd 100644 --- a/superset-frontend/src/api/dataset.ts +++ b/superset-frontend/src/api/dataset.ts @@ -41,6 +41,7 @@ export const getByUser = async (userId: number) => { export const put = async ( datasetId: number, + dbId: number, sql: string, columns: Array>, overrideColumns: boolean, @@ -50,6 +51,7 @@ export const put = async ( const body = JSON.stringify({ sql, columns, + database_id: dbId, }); const data: JsonResponse = await SupersetClient.put({ diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index b8406eb2cf..2703228739 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -75,6 +75,7 @@ class DatasetPostSchema(Schema): class DatasetPutSchema(Schema): table_name = fields.String(allow_none=True, validate=Length(1, 250)) + database_id = fields.Integer() sql = fields.String(allow_none=True) filter_select_enabled = fields.Boolean(allow_none=True) fetch_values_predicate = fields.String(allow_none=True, validate=Length(0, 1000))