[SIP-4] replace explorer ajax calls with `SupersetClient` (#5869)
* [superset-client] initialize SupersetClient in app setup * [core] replace explore ajax calls with SupersetClient * [core] fix SupersetClient explore tests * [core] remove _packages mistake directory * remove unused files * add yarn.lock * always render modal * [superset-client][jest] fix SaveModal_spec * [lint] remove unnecessary AbortController global * yarn.lock
This commit is contained in:
parent
dcfbae1ab9
commit
af0ffa44ab
|
|
@ -5,12 +5,12 @@ import thunk from 'redux-thunk';
|
|||
import { shallow, mount } from 'enzyme';
|
||||
import { Modal, Button, Radio } from 'react-bootstrap';
|
||||
import sinon from 'sinon';
|
||||
import fetchMock from 'fetch-mock';
|
||||
|
||||
import * as exploreUtils from '../../../../src/explore/exploreUtils';
|
||||
import * as saveModalActions from '../../../../src/explore/actions/saveModalActions';
|
||||
import SaveModal from '../../../../src/explore/components/SaveModal';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
import setupSupersetClient from '../../../helpers/setupSupersetClient';
|
||||
|
||||
describe('SaveModal', () => {
|
||||
const middlewares = [thunk];
|
||||
|
|
@ -44,9 +44,11 @@ describe('SaveModal', () => {
|
|||
},
|
||||
value: 'mock value',
|
||||
};
|
||||
const getWrapper = () => (shallow(<SaveModal {...defaultProps} />, {
|
||||
context: { store },
|
||||
}).dive());
|
||||
|
||||
const getWrapper = () =>
|
||||
shallow(<SaveModal {...defaultProps} />, {
|
||||
context: { store },
|
||||
}).dive();
|
||||
|
||||
it('renders a Modal with 7 inputs and 2 buttons', () => {
|
||||
const wrapper = getWrapper();
|
||||
|
|
@ -115,13 +117,17 @@ describe('SaveModal', () => {
|
|||
|
||||
describe('saveOrOverwrite', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(exploreUtils, 'getExploreUrlAndPayload').callsFake(() => ({ url: 'mockURL', payload: defaultProps.form_data }));
|
||||
sinon.stub(saveModalActions, 'saveSlice').callsFake(() => {
|
||||
const d = $.Deferred();
|
||||
d.resolve('done');
|
||||
return d.promise();
|
||||
});
|
||||
sinon
|
||||
.stub(exploreUtils, 'getExploreUrlAndPayload')
|
||||
.callsFake(() => ({ url: 'mockURL', payload: defaultProps.form_data }));
|
||||
|
||||
sinon
|
||||
.stub(saveModalActions, 'saveSlice')
|
||||
.callsFake(() =>
|
||||
Promise.resolve({ data: { dashboard: '/mock/', slice: { slice_url: '/mock/' } } }),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
exploreUtils.getExploreUrlAndPayload.restore();
|
||||
saveModalActions.saveSlice.restore();
|
||||
|
|
@ -133,6 +139,7 @@ describe('SaveModal', () => {
|
|||
const args = saveModalActions.saveSlice.getCall(0).args;
|
||||
expect(args[0]).toEqual(defaultProps.form_data);
|
||||
});
|
||||
|
||||
it('existing dashboard', () => {
|
||||
const wrapper = getWrapper();
|
||||
const saveToDashboardId = 100;
|
||||
|
|
@ -146,6 +153,7 @@ describe('SaveModal', () => {
|
|||
const args = saveModalActions.saveSlice.getCall(0).args;
|
||||
expect(args[1].save_to_dashboard_id).toBe(saveToDashboardId);
|
||||
});
|
||||
|
||||
it('new dashboard', () => {
|
||||
const wrapper = getWrapper();
|
||||
const newDashboardName = 'new dashboard name';
|
||||
|
|
@ -161,52 +169,68 @@ describe('SaveModal', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('should fetchDashboards', () => {
|
||||
describe('fetchDashboards', () => {
|
||||
let dispatch;
|
||||
let request;
|
||||
let ajaxStub;
|
||||
let actionThunk;
|
||||
const userID = 1;
|
||||
|
||||
const mockDashboardData = {
|
||||
pks: ['id'],
|
||||
result: [{ id: 'id', dashboard_title: 'dashboard title' }],
|
||||
};
|
||||
|
||||
const saveEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`;
|
||||
|
||||
beforeAll(() => {
|
||||
setupSupersetClient();
|
||||
fetchMock.get(saveEndpoint, mockDashboardData);
|
||||
});
|
||||
|
||||
afterAll(fetchMock.restore);
|
||||
|
||||
beforeEach(() => {
|
||||
dispatch = sinon.spy();
|
||||
ajaxStub = sinon.stub($, 'ajax');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ajaxStub.restore();
|
||||
fetchMock.resetHistory();
|
||||
});
|
||||
const mockDashboardData = {
|
||||
pks: ['value'],
|
||||
result: [
|
||||
{ dashboard_title: 'dashboard title' },
|
||||
],
|
||||
};
|
||||
|
||||
const makeRequest = () => {
|
||||
request = saveModalActions.fetchDashboards(userID);
|
||||
request(dispatch);
|
||||
actionThunk = saveModalActions.fetchDashboards(userID);
|
||||
return actionThunk(dispatch);
|
||||
};
|
||||
|
||||
it('makes the ajax request', () => {
|
||||
makeRequest();
|
||||
expect(ajaxStub.callCount).toBe(1);
|
||||
});
|
||||
it('makes the fetch request', () => (
|
||||
makeRequest().then(() => {
|
||||
expect(fetchMock.calls(saveEndpoint)).toHaveLength(1);
|
||||
|
||||
it('calls correct url', () => {
|
||||
const url = '/dashboardasync/api/read?_flt_0_owners=' + userID;
|
||||
makeRequest();
|
||||
expect(ajaxStub.getCall(0).args[0].url).toBe(url);
|
||||
});
|
||||
return Promise.resolve();
|
||||
})
|
||||
));
|
||||
|
||||
it('calls correct actions on success', () => (
|
||||
makeRequest().then(() => {
|
||||
expect(dispatch.callCount).toBe(1);
|
||||
expect(dispatch.getCall(0).args[0].type).toBe(
|
||||
saveModalActions.FETCH_DASHBOARDS_SUCCEEDED,
|
||||
);
|
||||
|
||||
return Promise.resolve();
|
||||
})
|
||||
));
|
||||
|
||||
it('calls correct actions on error', () => {
|
||||
ajaxStub.yieldsTo('error', { responseJSON: { error: 'error text' } });
|
||||
makeRequest();
|
||||
expect(dispatch.callCount).toBe(1);
|
||||
expect(dispatch.getCall(0).args[0].type).toBe(saveModalActions.FETCH_DASHBOARDS_FAILED);
|
||||
});
|
||||
fetchMock.get(saveEndpoint, { throws: 'error' }, { overwriteRoutes: true });
|
||||
|
||||
it('calls correct actions on success', () => {
|
||||
ajaxStub.yieldsTo('success', mockDashboardData);
|
||||
makeRequest();
|
||||
expect(dispatch.callCount).toBe(1);
|
||||
expect(dispatch.getCall(0).args[0].type).toBe(saveModalActions.FETCH_DASHBOARDS_SUCCEEDED);
|
||||
return makeRequest().then(() => {
|
||||
expect(dispatch.callCount).toBe(1);
|
||||
expect(dispatch.getCall(0).args[0].type).toBe(saveModalActions.FETCH_DASHBOARDS_FAILED);
|
||||
|
||||
fetchMock.get(saveEndpoint, mockDashboardData, { overwriteRoutes: true });
|
||||
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint global-require: 0, no-console: 0 */
|
||||
import $ from 'jquery';
|
||||
import { SupersetClient } from '@superset-ui/core';
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only';
|
||||
import { SupersetClient } from '@superset-ui/core';
|
||||
|
||||
import airbnb from './modules/colorSchemes/airbnb';
|
||||
import categoricalSchemes from './modules/colorSchemes/categorical';
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ export default class ModalTrigger extends React.Component {
|
|||
}
|
||||
|
||||
close() {
|
||||
this.setState({ showModal: false });
|
||||
this.setState(() => ({ showModal: false }));
|
||||
}
|
||||
|
||||
open(e) {
|
||||
e.preventDefault();
|
||||
this.props.beforeOpen();
|
||||
this.setState({ showModal: true });
|
||||
this.setState(() => ({ showModal: true }));
|
||||
}
|
||||
renderModal() {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* eslint camelcase: 0 */
|
||||
const $ = window.$ = require('jquery');
|
||||
import { SupersetClient } from '@superset-ui/core';
|
||||
import { addDangerToast } from '../../messageToasts/actions';
|
||||
import { t } from '../../locales';
|
||||
|
||||
const FAVESTAR_BASE_URL = '/superset/favstar/slice';
|
||||
|
||||
|
|
@ -50,24 +52,6 @@ export function resetControls() {
|
|||
return { type: RESET_FIELDS };
|
||||
}
|
||||
|
||||
export function fetchDatasources() {
|
||||
return function (dispatch) {
|
||||
dispatch(fetchDatasourcesStarted());
|
||||
const url = '/superset/datasources/';
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
success: (data) => {
|
||||
dispatch(setDatasources(data));
|
||||
dispatch(fetchDatasourcesSucceeded());
|
||||
},
|
||||
error(error) {
|
||||
dispatch(fetchDatasourcesFailed(error.responseJSON.error));
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const TOGGLE_FAVE_STAR = 'TOGGLE_FAVE_STAR';
|
||||
export function toggleFaveStar(isStarred) {
|
||||
return { type: TOGGLE_FAVE_STAR, isStarred };
|
||||
|
|
@ -76,9 +60,8 @@ export function toggleFaveStar(isStarred) {
|
|||
export const FETCH_FAVE_STAR = 'FETCH_FAVE_STAR';
|
||||
export function fetchFaveStar(sliceId) {
|
||||
return function (dispatch) {
|
||||
const url = `${FAVESTAR_BASE_URL}/${sliceId}/count`;
|
||||
$.get(url, (data) => {
|
||||
if (data.count > 0) {
|
||||
SupersetClient.get({ endpoint: `${FAVESTAR_BASE_URL}/${sliceId}/count` }).then(({ json }) => {
|
||||
if (json.count > 0) {
|
||||
dispatch(toggleFaveStar(true));
|
||||
}
|
||||
});
|
||||
|
|
@ -89,9 +72,9 @@ export const SAVE_FAVE_STAR = 'SAVE_FAVE_STAR';
|
|||
export function saveFaveStar(sliceId, isStarred) {
|
||||
return function (dispatch) {
|
||||
const urlSuffix = isStarred ? 'unselect' : 'select';
|
||||
const url = `${FAVESTAR_BASE_URL}/${sliceId}/${urlSuffix}/`;
|
||||
$.get(url);
|
||||
dispatch(toggleFaveStar(!isStarred));
|
||||
SupersetClient.get({ endpoint: `${FAVESTAR_BASE_URL}/${sliceId}/${urlSuffix}/` })
|
||||
.then(() => dispatch(toggleFaveStar(!isStarred)))
|
||||
.catch(() => dispatch(addDangerToast(t('An error occurred while starring this chart'))));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { SupersetClient } from '@superset-ui/core';
|
||||
import { getExploreUrlAndPayload } from '../exploreUtils';
|
||||
|
||||
const $ = window.$ = require('jquery');
|
||||
|
||||
export const FETCH_DASHBOARDS_SUCCEEDED = 'FETCH_DASHBOARDS_SUCCEEDED';
|
||||
export function fetchDashboardsSucceeded(choices) {
|
||||
return { type: FETCH_DASHBOARDS_SUCCEEDED, choices };
|
||||
|
|
@ -13,22 +12,19 @@ export function fetchDashboardsFailed(userId) {
|
|||
}
|
||||
|
||||
export function fetchDashboards(userId) {
|
||||
return function (dispatch) {
|
||||
const url = '/dashboardasync/api/read?_flt_0_owners=' + userId;
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
success: (data) => {
|
||||
const choices = [];
|
||||
for (let i = 0; i < data.pks.length; i++) {
|
||||
choices.push({ value: data.pks[i], label: data.result[i].dashboard_title });
|
||||
}
|
||||
dispatch(fetchDashboardsSucceeded(choices));
|
||||
},
|
||||
error: () => {
|
||||
dispatch(fetchDashboardsFailed(userId));
|
||||
},
|
||||
});
|
||||
return function fetchDashboardsThunk(dispatch) {
|
||||
return SupersetClient.get({
|
||||
endpoint: `/dashboardasync/api/read?_flt_0_owners=${userId}`,
|
||||
})
|
||||
.then(({ json }) => {
|
||||
const choices = json.pks.map((id, index) => ({
|
||||
value: id,
|
||||
label: (json.result[index] || {}).dashboard_title,
|
||||
}));
|
||||
|
||||
return dispatch(fetchDashboardsSucceeded(choices));
|
||||
})
|
||||
.catch(() => dispatch(fetchDashboardsFailed(userId)));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -55,18 +51,9 @@ export function saveSlice(formData, requestParams) {
|
|||
curUrl: null,
|
||||
requestParams,
|
||||
});
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
data: {
|
||||
form_data: JSON.stringify(payload),
|
||||
},
|
||||
success: ((data) => {
|
||||
dispatch(saveSliceSuccess(data));
|
||||
}),
|
||||
error: (() => {
|
||||
dispatch(saveSliceFailed());
|
||||
}),
|
||||
});
|
||||
|
||||
return SupersetClient.post({ url, postPayload: { form_data: payload } })
|
||||
.then(({ json }) => dispatch(saveSliceSuccess(json)))
|
||||
.catch(() => dispatch(saveSliceFailed()));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { FormGroup } from 'react-bootstrap';
|
||||
import VirtualizedSelect from 'react-virtualized-select';
|
||||
import { SupersetClient } from '@superset-ui/core';
|
||||
|
||||
import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../AdhocFilter';
|
||||
import adhocMetricType from '../propTypes/adhocMetricType';
|
||||
|
|
@ -19,16 +20,16 @@ import OnPasteSelect from '../../components/OnPasteSelect';
|
|||
import SelectControl from './controls/SelectControl';
|
||||
import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
|
||||
|
||||
const $ = require('jquery');
|
||||
|
||||
const propTypes = {
|
||||
adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
options: PropTypes.arrayOf(PropTypes.oneOfType([
|
||||
columnType,
|
||||
PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
|
||||
adhocMetricType,
|
||||
])).isRequired,
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([
|
||||
columnType,
|
||||
PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
|
||||
adhocMetricType,
|
||||
]),
|
||||
).isRequired,
|
||||
onHeightChange: PropTypes.func.isRequired,
|
||||
datasource: PropTypes.object,
|
||||
};
|
||||
|
|
@ -64,6 +65,7 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
this.state = {
|
||||
suggestions: [],
|
||||
multiComparatorHeight: SINGLE_LINE_SELECT_CONTROL_HEIGHT,
|
||||
abortActiveRequest: null,
|
||||
};
|
||||
|
||||
this.selectProps = {
|
||||
|
|
@ -102,11 +104,13 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
subject = option.saved_metric_name || option.label;
|
||||
clause = CLAUSES.HAVING;
|
||||
}
|
||||
this.props.onChange(this.props.adhocFilter.duplicateWith({
|
||||
subject,
|
||||
clause,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}));
|
||||
this.props.onChange(
|
||||
this.props.adhocFilter.duplicateWith({
|
||||
subject,
|
||||
clause,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
onOperatorChange(operator) {
|
||||
|
|
@ -115,17 +119,19 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
// convert between list of comparators and individual comparators
|
||||
// (e.g. `in ('North America', 'Africa')` to `== 'North America'`)
|
||||
if (MULTI_OPERATORS.indexOf(operator.operator) >= 0) {
|
||||
newComparator = Array.isArray(currentComparator) ?
|
||||
currentComparator :
|
||||
[currentComparator].filter(element => element);
|
||||
newComparator = Array.isArray(currentComparator)
|
||||
? currentComparator
|
||||
: [currentComparator].filter(element => element);
|
||||
} else {
|
||||
newComparator = Array.isArray(currentComparator) ? currentComparator[0] : currentComparator;
|
||||
}
|
||||
this.props.onChange(this.props.adhocFilter.duplicateWith({
|
||||
operator: operator && operator.operator,
|
||||
comparator: newComparator,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}));
|
||||
this.props.onChange(
|
||||
this.props.adhocFilter.duplicateWith({
|
||||
operator: operator && operator.operator,
|
||||
comparator: newComparator,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
onInputComparatorChange(event) {
|
||||
|
|
@ -133,23 +139,26 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
}
|
||||
|
||||
onComparatorChange(comparator) {
|
||||
this.props.onChange(this.props.adhocFilter.duplicateWith({
|
||||
comparator,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}));
|
||||
this.props.onChange(
|
||||
this.props.adhocFilter.duplicateWith({
|
||||
comparator,
|
||||
expressionType: EXPRESSION_TYPES.SIMPLE,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
handleMultiComparatorInputHeightChange() {
|
||||
if (this.multiComparatorComponent) {
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
const multiComparatorDOMNode = this.multiComparatorComponent._selectRef &&
|
||||
const multiComparatorDOMNode =
|
||||
this.multiComparatorComponent._selectRef &&
|
||||
this.multiComparatorComponent._selectRef.select &&
|
||||
this.multiComparatorComponent._selectRef.select.control;
|
||||
if (multiComparatorDOMNode) {
|
||||
if (multiComparatorDOMNode.clientHeight !== this.state.multiComparatorHeight) {
|
||||
this.props.onHeightChange((
|
||||
multiComparatorDOMNode.clientHeight - this.state.multiComparatorHeight
|
||||
));
|
||||
this.props.onHeightChange(
|
||||
multiComparatorDOMNode.clientHeight - this.state.multiComparatorHeight,
|
||||
);
|
||||
this.setState({ multiComparatorHeight: multiComparatorDOMNode.clientHeight });
|
||||
}
|
||||
}
|
||||
|
|
@ -162,15 +171,19 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
const having = this.props.adhocFilter.clause === CLAUSES.HAVING;
|
||||
|
||||
if (col && datasource && datasource.filter_select && !having) {
|
||||
if (this.state.activeRequest) {
|
||||
this.state.activeRequest.abort();
|
||||
if (this.state.abortActiveRequest) {
|
||||
this.state.abortActiveRequest();
|
||||
}
|
||||
this.setState({
|
||||
activeRequest: $.ajax({
|
||||
type: 'GET',
|
||||
url: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`,
|
||||
success: data => this.setState({ suggestions: data, activeRequest: null }),
|
||||
}),
|
||||
|
||||
const controller = new AbortController();
|
||||
const { signal } = controller;
|
||||
this.setState({ abortActiveRequest: controller.abort });
|
||||
|
||||
SupersetClient.get({
|
||||
signal,
|
||||
endpoint: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`,
|
||||
}).then(({ json }) => {
|
||||
this.setState(() => ({ suggestions: json, abortActiveRequest: null }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -179,10 +192,8 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
return !(
|
||||
(this.props.datasource.type === 'druid' && TABLE_ONLY_OPERATORS.indexOf(operator) >= 0) ||
|
||||
(this.props.datasource.type === 'table' && DRUID_ONLY_OPERATORS.indexOf(operator) >= 0) ||
|
||||
(
|
||||
this.props.adhocFilter.clause === CLAUSES.HAVING &&
|
||||
HAVING_OPERATORS.indexOf(operator) === -1
|
||||
)
|
||||
(this.props.adhocFilter.clause === CLAUSES.HAVING &&
|
||||
HAVING_OPERATORS.indexOf(operator) === -1)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -204,9 +215,7 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
let subjectSelectProps = {
|
||||
value: adhocFilter.subject ? { value: adhocFilter.subject } : undefined,
|
||||
onChange: this.onSubjectChange,
|
||||
optionRenderer: VirtualizedRendererWrap(option => (
|
||||
<FilterDefinitionOption option={option} />
|
||||
)),
|
||||
optionRenderer: VirtualizedRendererWrap(option => <FilterDefinitionOption option={option} />),
|
||||
valueRenderer: option => <span>{option.value}</span>,
|
||||
valueKey: 'filterOptionName',
|
||||
noResultsText: t('No such column found. To filter on a metric, try the Custom SQL tab.'),
|
||||
|
|
@ -224,28 +233,23 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
|||
// becomes a rather complicated problem)
|
||||
subjectSelectProps = {
|
||||
...subjectSelectProps,
|
||||
placeholder: adhocFilter.clause === CLAUSES.WHERE ?
|
||||
t('%s column(s)', options.length) :
|
||||
t('To filter on a metric, use Custom SQL tab.'),
|
||||
placeholder:
|
||||
adhocFilter.clause === CLAUSES.WHERE
|
||||
? t('%s column(s)', options.length)
|
||||
: t('To filter on a metric, use Custom SQL tab.'),
|
||||
options: options.filter(option => option.column_name),
|
||||
};
|
||||
}
|
||||
|
||||
const operatorSelectProps = {
|
||||
placeholder: t('%s operators(s)', Object.keys(OPERATORS).length),
|
||||
options: Object.keys(OPERATORS).filter(this.isOperatorRelevant).map((
|
||||
operator => ({ operator })
|
||||
)),
|
||||
options: Object.keys(OPERATORS)
|
||||
.filter(this.isOperatorRelevant)
|
||||
.map(operator => ({ operator })),
|
||||
value: adhocFilter.operator,
|
||||
onChange: this.onOperatorChange,
|
||||
optionRenderer: VirtualizedRendererWrap((
|
||||
operator => translateOperator(operator.operator)
|
||||
)),
|
||||
valueRenderer: operator => (
|
||||
<span>
|
||||
{translateOperator(operator.operator)}
|
||||
</span>
|
||||
),
|
||||
optionRenderer: VirtualizedRendererWrap(operator => translateOperator(operator.operator)),
|
||||
valueRenderer: operator => <span>{translateOperator(operator.operator)}</span>,
|
||||
valueKey: 'operator',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import SyntaxHighlighter, { registerLanguage } from 'react-syntax-highlighter/dist/light';
|
||||
import html from 'react-syntax-highlighter/languages/hljs/htmlbars';
|
||||
import markdown from 'react-syntax-highlighter/languages/hljs/markdown';
|
||||
import sql from 'react-syntax-highlighter/languages/hljs/sql';
|
||||
import json from 'react-syntax-highlighter/languages/hljs/json';
|
||||
import SyntaxHighlighter, { registerLanguage } from 'react-syntax-highlighter/light';
|
||||
import htmlSyntax from 'react-syntax-highlighter/languages/hljs/htmlbars';
|
||||
import markdownSyntax from 'react-syntax-highlighter/languages/hljs/markdown';
|
||||
import sqlSyntax from 'react-syntax-highlighter/languages/hljs/sql';
|
||||
import jsonSyntax from 'react-syntax-highlighter/languages/hljs/json';
|
||||
import github from 'react-syntax-highlighter/styles/hljs/github';
|
||||
import { DropdownButton, MenuItem, Row, Col, FormControl } from 'react-bootstrap';
|
||||
import { Table } from 'reactable';
|
||||
import $ from 'jquery';
|
||||
import { SupersetClient } from '@superset-ui/core';
|
||||
|
||||
import CopyToClipboard from './../../components/CopyToClipboard';
|
||||
import { getExploreUrlAndPayload } from '../exploreUtils';
|
||||
|
|
@ -19,10 +19,10 @@ import Button from '../../components/Button';
|
|||
import { t } from '../../locales';
|
||||
import RowCountLabel from './RowCountLabel';
|
||||
|
||||
registerLanguage('markdown', markdown);
|
||||
registerLanguage('html', html);
|
||||
registerLanguage('sql', sql);
|
||||
registerLanguage('json', json);
|
||||
registerLanguage('markdown', markdownSyntax);
|
||||
registerLanguage('html', htmlSyntax);
|
||||
registerLanguage('sql', sqlSyntax);
|
||||
registerLanguage('json', jsonSyntax);
|
||||
|
||||
const propTypes = {
|
||||
onOpenInEditor: PropTypes.func,
|
||||
|
|
@ -57,28 +57,25 @@ export default class DisplayQueryButton extends React.PureComponent {
|
|||
formData: this.props.latestQueryFormData,
|
||||
endpointType,
|
||||
});
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
SupersetClient.post({
|
||||
url,
|
||||
data: {
|
||||
form_data: JSON.stringify(payload),
|
||||
},
|
||||
success: (data) => {
|
||||
postPayload: { form_data: payload },
|
||||
})
|
||||
.then(({ json }) => {
|
||||
this.setState({
|
||||
language: data.language,
|
||||
query: data.query,
|
||||
data: data.data,
|
||||
language: json.language,
|
||||
query: json.query,
|
||||
data: json.data,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
},
|
||||
error: (data) => {
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
error: data.responseJSON ? data.responseJSON.error : t('Error...'),
|
||||
error: error.error || error.statusText || t('Sorry, An error occurred'),
|
||||
isLoading: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
changeFilterText(event) {
|
||||
this.setState({ filterText: event.target.value });
|
||||
|
|
@ -113,11 +110,7 @@ export default class DisplayQueryButton extends React.PureComponent {
|
|||
}
|
||||
renderResultsModalBody() {
|
||||
if (this.state.isLoading) {
|
||||
return (<img
|
||||
className="loading"
|
||||
alt={t('Loading...')}
|
||||
src="/static/assets/images/loading.gif"
|
||||
/>);
|
||||
return <Loading />;
|
||||
} else if (this.state.error) {
|
||||
return <pre>{this.state.error}</pre>;
|
||||
} else if (this.state.data) {
|
||||
|
|
@ -213,12 +206,14 @@ export default class DisplayQueryButton extends React.PureComponent {
|
|||
modalBody={this.renderSamplesModalBody()}
|
||||
eventKey="2"
|
||||
/>
|
||||
{this.state.sqlSupported && <MenuItem
|
||||
eventKey="3"
|
||||
onClick={this.redirectSQLLab.bind(this)}
|
||||
>
|
||||
{t('Run in SQL Lab')}
|
||||
</MenuItem>}
|
||||
{this.state.sqlSupported && (
|
||||
<MenuItem
|
||||
eventKey="3"
|
||||
onClick={this.redirectSQLLab.bind(this)}
|
||||
>
|
||||
{t('Run in SQL Lab')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</DropdownButton>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class SaveModal extends React.Component {
|
|||
sliceParams.add_to_dash = addToDash;
|
||||
let dashboard = null;
|
||||
switch (addToDash) {
|
||||
case ('existing'):
|
||||
case 'existing':
|
||||
dashboard = this.state.saveToDashboardId;
|
||||
if (!dashboard) {
|
||||
this.setState({ alert: t('Please select a dashboard') });
|
||||
|
|
@ -93,7 +93,7 @@ class SaveModal extends React.Component {
|
|||
}
|
||||
sliceParams.save_to_dashboard_id = dashboard;
|
||||
break;
|
||||
case ('new'):
|
||||
case 'new':
|
||||
dashboard = this.state.newDashboardName;
|
||||
if (dashboard === '') {
|
||||
this.setState({ alert: t('Please enter a dashboard name') });
|
||||
|
|
@ -106,15 +106,14 @@ class SaveModal extends React.Component {
|
|||
}
|
||||
sliceParams.goto_dash = gotodash;
|
||||
|
||||
this.props.actions.saveSlice(this.props.form_data, sliceParams)
|
||||
.then((data) => {
|
||||
// Go to new slice url or dashboard url
|
||||
if (gotodash) {
|
||||
window.location = supersetURL(data.dashboard);
|
||||
} else {
|
||||
window.location = data.slice.slice_url;
|
||||
}
|
||||
});
|
||||
this.props.actions.saveSlice(this.props.form_data, sliceParams).then(({ data }) => {
|
||||
// Go to new slice url or dashboard url
|
||||
if (gotodash) {
|
||||
window.location = supersetURL(data.dashboard);
|
||||
} else {
|
||||
window.location = data.slice.slice_url;
|
||||
}
|
||||
});
|
||||
this.props.onHide();
|
||||
}
|
||||
removeAlert() {
|
||||
|
|
@ -126,18 +125,12 @@ class SaveModal extends React.Component {
|
|||
render() {
|
||||
const canNotSaveToDash = EXPLORE_ONLY_VIZ_TYPE.indexOf(this.state.vizType) > -1;
|
||||
return (
|
||||
<Modal
|
||||
show
|
||||
onHide={this.props.onHide}
|
||||
bsStyle="large"
|
||||
>
|
||||
<Modal show onHide={this.props.onHide} bsStyle="large">
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
{t('Save A Chart')}
|
||||
</Modal.Title>
|
||||
<Modal.Title>{t('Save A Chart')}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
{(this.state.alert || this.props.alert) &&
|
||||
{(this.state.alert || this.props.alert) && (
|
||||
<Alert>
|
||||
{this.state.alert ? this.state.alert : this.props.alert}
|
||||
<i
|
||||
|
|
@ -146,8 +139,8 @@ class SaveModal extends React.Component {
|
|||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
</Alert>
|
||||
}
|
||||
{this.props.slice &&
|
||||
)}
|
||||
{this.props.slice && (
|
||||
<Radio
|
||||
id="overwrite-radio"
|
||||
disabled={!this.props.can_overwrite}
|
||||
|
|
@ -156,14 +149,16 @@ class SaveModal extends React.Component {
|
|||
>
|
||||
{t('Overwrite chart %s', this.props.slice.slice_name)}
|
||||
</Radio>
|
||||
}
|
||||
)}
|
||||
|
||||
<Radio
|
||||
id="saveas-radio"
|
||||
inline
|
||||
checked={this.state.action === 'saveas'}
|
||||
onChange={this.changeAction.bind(this, 'saveas')}
|
||||
> {t('Save as')}
|
||||
>
|
||||
{' '}
|
||||
{t('Save as')}
|
||||
</Radio>
|
||||
<input
|
||||
name="new_slice_name"
|
||||
|
|
@ -172,7 +167,6 @@ class SaveModal extends React.Component {
|
|||
onFocus={this.changeAction.bind(this, 'saveas')}
|
||||
/>
|
||||
|
||||
|
||||
<br />
|
||||
<hr />
|
||||
|
||||
|
|
@ -199,7 +193,7 @@ class SaveModal extends React.Component {
|
|||
onChange={this.onChange.bind(this, 'saveToDashboardId')}
|
||||
autoSize={false}
|
||||
value={this.state.saveToDashboardId}
|
||||
placeholder={t('Select Dashboard')}
|
||||
placeholder="Select Dashboard"
|
||||
/>
|
||||
|
||||
<Radio
|
||||
|
|
@ -217,7 +211,6 @@ class SaveModal extends React.Component {
|
|||
onFocus={this.changeDash.bind(this, 'new')}
|
||||
placeholder={t('[dashboard name]')}
|
||||
/>
|
||||
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
|
|
@ -258,4 +251,7 @@ function mapStateToProps({ explore, saveModal }) {
|
|||
}
|
||||
|
||||
export { SaveModal };
|
||||
export default connect(mapStateToProps, () => ({}))(SaveModal);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
() => ({}),
|
||||
)(SaveModal);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue