mirror of
https://github.com/apache/superset.git
synced 2026-08-05 21:42:48 +00:00
fix(sqllab): save datasets with template parameters (#33195)
This commit is contained in:
@@ -29,6 +29,7 @@ import fetchMock from 'fetch-mock';
|
||||
import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal';
|
||||
import { createDatasource } from 'src/SqlLab/actions/sqlLab';
|
||||
import { user, testQuery, mockdatasets } from 'src/SqlLab/fixtures';
|
||||
import { FeatureFlag } from '@superset-ui/core';
|
||||
|
||||
const mockedProps = {
|
||||
visible: true,
|
||||
@@ -250,4 +251,88 @@ describe('SaveDatasetModal', () => {
|
||||
templateParams: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not renders a checkbox button when template processing is disabled', () => {
|
||||
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
|
||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders a checkbox button when template processing is enabled', () => {
|
||||
// @ts-ignore
|
||||
global.featureFlags = {
|
||||
[FeatureFlag.EnableTemplateProcessing]: true,
|
||||
};
|
||||
render(<SaveDatasetModal {...mockedProps} />, { useRedux: true });
|
||||
expect(screen.getByRole('checkbox')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('correctly includes template parameters when template processing is enabled', () => {
|
||||
// @ts-ignore
|
||||
global.featureFlags = {
|
||||
[FeatureFlag.EnableTemplateProcessing]: true,
|
||||
};
|
||||
const propsWithTemplateParam = {
|
||||
...mockedProps,
|
||||
datasource: {
|
||||
...testQuery,
|
||||
templateParams: JSON.stringify({ my_param: 12 }),
|
||||
},
|
||||
};
|
||||
render(<SaveDatasetModal {...propsWithTemplateParam} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
const inputFieldText = screen.getByDisplayValue(/unimportant/i);
|
||||
fireEvent.change(inputFieldText, { target: { value: 'my dataset' } });
|
||||
|
||||
userEvent.click(screen.getByRole('checkbox'));
|
||||
|
||||
const saveConfirmationBtn = screen.getByRole('button', {
|
||||
name: /save/i,
|
||||
});
|
||||
userEvent.click(saveConfirmationBtn);
|
||||
|
||||
expect(createDatasource).toHaveBeenCalledWith({
|
||||
datasourceName: 'my dataset',
|
||||
dbId: 1,
|
||||
catalog: null,
|
||||
schema: 'main',
|
||||
sql: 'SELECT *',
|
||||
templateParams: JSON.stringify({ my_param: 12 }),
|
||||
});
|
||||
});
|
||||
|
||||
it('correctly excludes template parameters when template processing is enabled', () => {
|
||||
// @ts-ignore
|
||||
global.featureFlags = {
|
||||
[FeatureFlag.EnableTemplateProcessing]: true,
|
||||
};
|
||||
const propsWithTemplateParam = {
|
||||
...mockedProps,
|
||||
datasource: {
|
||||
...testQuery,
|
||||
templateParams: JSON.stringify({ my_param: 12 }),
|
||||
},
|
||||
};
|
||||
render(<SaveDatasetModal {...propsWithTemplateParam} />, {
|
||||
useRedux: true,
|
||||
});
|
||||
const inputFieldText = screen.getByDisplayValue(/unimportant/i);
|
||||
fireEvent.change(inputFieldText, { target: { value: 'my dataset' } });
|
||||
|
||||
userEvent.click(screen.getByRole('checkbox'));
|
||||
|
||||
const saveConfirmationBtn = screen.getByRole('button', {
|
||||
name: /save/i,
|
||||
});
|
||||
userEvent.click(saveConfirmationBtn);
|
||||
|
||||
expect(createDatasource).toHaveBeenCalledWith({
|
||||
datasourceName: 'my dataset',
|
||||
dbId: 1,
|
||||
catalog: null,
|
||||
schema: 'main',
|
||||
sql: 'SELECT *',
|
||||
templateParams: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,6 +24,7 @@ import { AsyncSelect } from 'src/components';
|
||||
import { Input } from 'src/components/Input';
|
||||
import StyledModal from 'src/components/Modal';
|
||||
import Button from 'src/components/Button';
|
||||
import Checkbox from 'src/components/Checkbox';
|
||||
import {
|
||||
styled,
|
||||
t,
|
||||
@@ -33,6 +34,8 @@ import {
|
||||
QueryResponse,
|
||||
QueryFormData,
|
||||
VizType,
|
||||
FeatureFlag,
|
||||
isFeatureEnabled,
|
||||
} from '@superset-ui/core';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -185,6 +188,8 @@ export const SaveDatasetModal = ({
|
||||
|
||||
const user = useSelector<SqlLabRootState, User>(state => state.user);
|
||||
const dispatch = useDispatch<(dispatch: any) => Promise<JsonObject>>();
|
||||
const [includeTemplateParameters, setIncludeTemplateParameters] =
|
||||
useState(false);
|
||||
|
||||
const createWindow = (url: string) => {
|
||||
if (openWindow) {
|
||||
@@ -285,14 +290,21 @@ export const SaveDatasetModal = ({
|
||||
// Remove the special filters entry from the templateParams
|
||||
// before saving the dataset.
|
||||
let templateParams;
|
||||
if (typeof datasource?.templateParams === 'string') {
|
||||
const p = JSON.parse(datasource.templateParams);
|
||||
/* eslint-disable-next-line no-underscore-dangle */
|
||||
if (p._filters) {
|
||||
if (
|
||||
typeof datasource?.templateParams === 'string' &&
|
||||
includeTemplateParameters
|
||||
) {
|
||||
try {
|
||||
const p = JSON.parse(datasource.templateParams);
|
||||
/* eslint-disable-next-line no-underscore-dangle */
|
||||
delete p._filters;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
if (p._filters) {
|
||||
/* eslint-disable-next-line no-underscore-dangle */
|
||||
delete p._filters;
|
||||
}
|
||||
templateParams = JSON.stringify(p);
|
||||
} catch (e) {
|
||||
// malformed templateParams, do not include it
|
||||
templateParams = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +374,27 @@ export const SaveDatasetModal = ({
|
||||
title={t('Save or Overwrite Dataset')}
|
||||
onHide={onHide}
|
||||
footer={
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
{isFeatureEnabled(FeatureFlag.EnableTemplateProcessing) && (
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Checkbox
|
||||
checked={includeTemplateParameters}
|
||||
onChange={checked =>
|
||||
setIncludeTemplateParameters(checked ?? false)
|
||||
}
|
||||
/>
|
||||
<span style={{ marginLeft: '5px' }}>
|
||||
{t('Include Template Parameters')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{newOrOverwrite === DatasetRadioState.SaveNew && (
|
||||
<Button
|
||||
disabled={disableSaveAndExploreBtn}
|
||||
@@ -389,7 +421,7 @@ export const SaveDatasetModal = ({
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Styles>
|
||||
|
||||
Reference in New Issue
Block a user