mirror of https://github.com/apache/superset.git
[superset-client][datasource editor] replace ajax with SupersetClient (#6134)
* [superset-client][datasource editor] replace ajax with SupersetClient * [superset-client][datasource control] replace ajax with SupersetClient * [superset-client][datasource editor] remove unused funcs in DatasourceControl * [superset-client][data source control] lint, remove toasts * [superset-client] fix DatasourceControl_spec * [superset-client] remove unneeded functional setState calls
This commit is contained in:
parent
546d150b91
commit
96228adda9
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||||
import { Tabs } from 'react-bootstrap';
|
import { Tabs } from 'react-bootstrap';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import $ from 'jquery';
|
import fetchMock from 'fetch-mock';
|
||||||
import sinon from 'sinon';
|
import thunk from 'redux-thunk';
|
||||||
|
|
||||||
import DatasourceEditor from '../../../src/datasource/DatasourceEditor';
|
import DatasourceEditor from '../../../src/datasource/DatasourceEditor';
|
||||||
import mockDatasource from '../../fixtures/mockDatasource';
|
import mockDatasource from '../../fixtures/mockDatasource';
|
||||||
|
@ -12,8 +12,9 @@ const props = {
|
||||||
datasource: mockDatasource['7__table'],
|
datasource: mockDatasource['7__table'],
|
||||||
addSuccessToast: () => {},
|
addSuccessToast: () => {},
|
||||||
addDangerToast: () => {},
|
addDangerToast: () => {},
|
||||||
onChange: sinon.spy(),
|
onChange: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const extraColumn = {
|
const extraColumn = {
|
||||||
column_name: 'new_column',
|
column_name: 'new_column',
|
||||||
type: 'VARCHAR(10)',
|
type: 'VARCHAR(10)',
|
||||||
|
@ -25,26 +26,23 @@ const extraColumn = {
|
||||||
groupby: true,
|
groupby: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DATASOURCE_ENDPOINT = 'glob:*/datasource/external_metadata/*';
|
||||||
|
|
||||||
describe('DatasourceEditor', () => {
|
describe('DatasourceEditor', () => {
|
||||||
const mockStore = configureStore([]);
|
const mockStore = configureStore([thunk]);
|
||||||
const store = mockStore({});
|
const store = mockStore({});
|
||||||
|
fetchMock.get(DATASOURCE_ENDPOINT, []);
|
||||||
|
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let el;
|
let el;
|
||||||
let ajaxStub;
|
|
||||||
let inst;
|
let inst;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ajaxStub = sinon.stub($, 'ajax');
|
|
||||||
el = <DatasourceEditor {...props} />;
|
el = <DatasourceEditor {...props} />;
|
||||||
wrapper = shallow(el, { context: { store } }).dive();
|
wrapper = shallow(el, { context: { store } }).dive();
|
||||||
inst = wrapper.instance();
|
inst = wrapper.instance();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
ajaxStub.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is valid', () => {
|
it('is valid', () => {
|
||||||
expect(React.isValidElement(el)).toBe(true);
|
expect(React.isValidElement(el)).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -53,12 +51,17 @@ describe('DatasourceEditor', () => {
|
||||||
expect(wrapper.find(Tabs)).toHaveLength(1);
|
expect(wrapper.find(Tabs)).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('makes an async request', () => {
|
it('makes an async request', (done) => {
|
||||||
wrapper.setState({ activeTabKey: 2 });
|
wrapper.setState({ activeTabKey: 2 });
|
||||||
const syncButton = wrapper.find('.sync-from-source');
|
const syncButton = wrapper.find('.sync-from-source');
|
||||||
expect(syncButton).toHaveLength(1);
|
expect(syncButton).toHaveLength(1);
|
||||||
syncButton.simulate('click');
|
syncButton.simulate('click');
|
||||||
expect(ajaxStub.calledOnce).toBe(true);
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1);
|
||||||
|
fetchMock.reset();
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('merges columns', () => {
|
it('merges columns', () => {
|
||||||
|
@ -67,5 +70,4 @@ describe('DatasourceEditor', () => {
|
||||||
inst.mergeColumns([extraColumn]);
|
inst.mergeColumns([extraColumn]);
|
||||||
expect(inst.state.databaseColumns).toHaveLength(numCols + 1);
|
expect(inst.state.databaseColumns).toHaveLength(numCols + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,8 @@ import React from 'react';
|
||||||
import { Modal } from 'react-bootstrap';
|
import { Modal } from 'react-bootstrap';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import $ from 'jquery';
|
import fetchMock from 'fetch-mock';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
import DatasourceModal from '../../../src/datasource/DatasourceModal';
|
import DatasourceModal from '../../../src/datasource/DatasourceModal';
|
||||||
|
@ -13,31 +14,30 @@ const props = {
|
||||||
datasource: mockDatasource['7__table'],
|
datasource: mockDatasource['7__table'],
|
||||||
addSuccessToast: () => {},
|
addSuccessToast: () => {},
|
||||||
addDangerToast: () => {},
|
addDangerToast: () => {},
|
||||||
onChange: sinon.spy(),
|
onChange: () => {},
|
||||||
show: true,
|
show: true,
|
||||||
onHide: () => {},
|
onHide: () => {},
|
||||||
|
onDatasourceSave: sinon.spy(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SAVE_ENDPOINT = 'glob:*/datasource/save/';
|
||||||
|
const SAVE_PAYLOAD = { new: 'data' };
|
||||||
|
|
||||||
describe('DatasourceModal', () => {
|
describe('DatasourceModal', () => {
|
||||||
const mockStore = configureStore([]);
|
const mockStore = configureStore([thunk]);
|
||||||
const store = mockStore({});
|
const store = mockStore({});
|
||||||
|
fetchMock.post(SAVE_ENDPOINT, SAVE_PAYLOAD);
|
||||||
|
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let el;
|
let el;
|
||||||
let ajaxStub;
|
|
||||||
let inst;
|
let inst;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ajaxStub = sinon.stub($, 'ajax');
|
|
||||||
el = <DatasourceModal {...props} />;
|
el = <DatasourceModal {...props} />;
|
||||||
wrapper = shallow(el, { context: { store } }).dive();
|
wrapper = shallow(el, { context: { store } }).dive();
|
||||||
inst = wrapper.instance();
|
inst = wrapper.instance();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
ajaxStub.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is valid', () => {
|
it('is valid', () => {
|
||||||
expect(React.isValidElement(el)).toBe(true);
|
expect(React.isValidElement(el)).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -50,8 +50,13 @@ describe('DatasourceModal', () => {
|
||||||
expect(wrapper.find(DatasourceEditor)).toHaveLength(1);
|
expect(wrapper.find(DatasourceEditor)).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('saves on confirm', () => {
|
it('saves on confirm', (done) => {
|
||||||
inst.onConfirmSave();
|
inst.onConfirmSave();
|
||||||
expect(ajaxStub.calledOnce).toBe(true);
|
setTimeout(() => {
|
||||||
|
expect(fetchMock.calls(SAVE_ENDPOINT)).toHaveLength(1);
|
||||||
|
expect(props.onDatasourceSave.getCall(0).args[0]).toEqual(SAVE_PAYLOAD);
|
||||||
|
fetchMock.reset();
|
||||||
|
done();
|
||||||
|
}, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('DatasourceControl', () => {
|
||||||
function setup() {
|
function setup() {
|
||||||
const mockStore = configureStore([]);
|
const mockStore = configureStore([]);
|
||||||
const store = mockStore({});
|
const store = mockStore({});
|
||||||
return shallow(<DatasourceControl {...defaultProps} />, { context: { store } }).dive();
|
return shallow(<DatasourceControl {...defaultProps} />, { context: { store } });
|
||||||
}
|
}
|
||||||
|
|
||||||
it('renders a Modal', () => {
|
it('renders a Modal', () => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Alert, Badge, Col, Label, Tabs, Tab, Well } from 'react-bootstrap';
|
import { Alert, Badge, Col, Label, Tabs, Tab, Well } from 'react-bootstrap';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import $ from 'jquery';
|
import { SupersetClient } from '@superset-ui/core';
|
||||||
|
|
||||||
import { t } from '../locales';
|
import { t } from '../locales';
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ function CollectionTabTitle({ title, collection }) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionTabTitle.propTypes = {
|
CollectionTabTitle.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
collection: PropTypes.array,
|
collection: PropTypes.array,
|
||||||
|
@ -159,6 +160,7 @@ function StackedField({ label, formElement }) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackedField.propTypes = {
|
StackedField.propTypes = {
|
||||||
label: PropTypes.string,
|
label: PropTypes.string,
|
||||||
formElement: PropTypes.node,
|
formElement: PropTypes.node,
|
||||||
|
@ -171,6 +173,7 @@ function FormContainer({ children }) {
|
||||||
</Well>
|
</Well>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FormContainer.propTypes = {
|
FormContainer.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
};
|
};
|
||||||
|
@ -181,9 +184,11 @@ const propTypes = {
|
||||||
addSuccessToast: PropTypes.func.isRequired,
|
addSuccessToast: PropTypes.func.isRequired,
|
||||||
addDangerToast: PropTypes.func.isRequired,
|
addDangerToast: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
onChange: () => {},
|
onChange: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DatasourceEditor extends React.PureComponent {
|
export class DatasourceEditor extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -206,6 +211,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
this.validateAndChange = this.validateAndChange.bind(this);
|
this.validateAndChange = this.validateAndChange.bind(this);
|
||||||
this.handleTabSelect = this.handleTabSelect.bind(this);
|
this.handleTabSelect = this.handleTabSelect.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange() {
|
onChange() {
|
||||||
const datasource = {
|
const datasource = {
|
||||||
...this.state.datasource,
|
...this.state.datasource,
|
||||||
|
@ -213,19 +219,24 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
};
|
};
|
||||||
this.props.onChange(datasource, this.state.errors);
|
this.props.onChange(datasource, this.state.errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDatasourceChange(newDatasource) {
|
onDatasourceChange(newDatasource) {
|
||||||
this.setState({ datasource: newDatasource }, this.validateAndChange);
|
this.setState({ datasource: newDatasource }, this.validateAndChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDatasourcePropChange(attr, value) {
|
onDatasourcePropChange(attr, value) {
|
||||||
const datasource = { ...this.state.datasource, [attr]: value };
|
const datasource = { ...this.state.datasource, [attr]: value };
|
||||||
this.setState({ datasource }, this.onDatasourceChange(datasource));
|
this.setState({ datasource }, this.onDatasourceChange(datasource));
|
||||||
}
|
}
|
||||||
|
|
||||||
setColumns(obj) {
|
setColumns(obj) {
|
||||||
this.setState(obj, this.validateAndChange);
|
this.setState(obj, this.validateAndChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateAndChange() {
|
validateAndChange() {
|
||||||
this.validate(this.onChange);
|
this.validate(this.onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
mergeColumns(cols) {
|
mergeColumns(cols) {
|
||||||
let { databaseColumns } = this.state;
|
let { databaseColumns } = this.state;
|
||||||
let hasChanged;
|
let hasChanged;
|
||||||
|
@ -248,29 +259,22 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syncMetadata() {
|
syncMetadata() {
|
||||||
const datasource = this.state.datasource;
|
const { datasource } = this.state;
|
||||||
const url = `/datasource/external_metadata/${datasource.type}/${datasource.id}/`;
|
|
||||||
this.setState({ metadataLoading: true });
|
this.setState({ metadataLoading: true });
|
||||||
const success = (data) => {
|
|
||||||
this.mergeColumns(data);
|
SupersetClient.get({
|
||||||
|
endpoint: `/datasource/external_metadata/${datasource.type}/${datasource.id}/`,
|
||||||
|
}).then(({ json }) => {
|
||||||
|
this.mergeColumns(json);
|
||||||
this.props.addSuccessToast(t('Metadata has been synced'));
|
this.props.addSuccessToast(t('Metadata has been synced'));
|
||||||
this.setState({ metadataLoading: false });
|
this.setState({ metadataLoading: false });
|
||||||
};
|
}).catch((error) => {
|
||||||
const error = (err) => {
|
const msg = error.error || error.statusText || t('An error has occurred');
|
||||||
let msg = t('An error has occurred');
|
|
||||||
if (err.responseJSON && err.responseJSON.error) {
|
|
||||||
msg = err.responseJSON.error;
|
|
||||||
}
|
|
||||||
this.props.addDangerToast(msg);
|
this.props.addDangerToast(msg);
|
||||||
this.setState({ metadataLoading: false });
|
this.setState({ metadataLoading: false });
|
||||||
};
|
|
||||||
$.ajax({
|
|
||||||
url,
|
|
||||||
type: 'GET',
|
|
||||||
success,
|
|
||||||
error,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
findDuplicates(arr, accessor) {
|
findDuplicates(arr, accessor) {
|
||||||
const seen = {};
|
const seen = {};
|
||||||
const dups = [];
|
const dups = [];
|
||||||
|
@ -284,6 +288,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
});
|
});
|
||||||
return dups;
|
return dups;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(callback) {
|
validate(callback) {
|
||||||
let errors = [];
|
let errors = [];
|
||||||
let dups;
|
let dups;
|
||||||
|
@ -305,9 +310,11 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
|
|
||||||
this.setState({ errors }, callback);
|
this.setState({ errors }, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTabSelect(activeTabKey) {
|
handleTabSelect(activeTabKey) {
|
||||||
this.setState({ activeTabKey });
|
this.setState({ activeTabKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSettingsFieldset() {
|
renderSettingsFieldset() {
|
||||||
const datasource = this.state.datasource;
|
const datasource = this.state.datasource;
|
||||||
return (
|
return (
|
||||||
|
@ -348,6 +355,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAdvancedFieldset() {
|
renderAdvancedFieldset() {
|
||||||
const datasource = this.state.datasource;
|
const datasource = this.state.datasource;
|
||||||
return (
|
return (
|
||||||
|
@ -388,6 +396,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</Fieldset>);
|
</Fieldset>);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSpatialTab() {
|
renderSpatialTab() {
|
||||||
const { datasource } = this.state;
|
const { datasource } = this.state;
|
||||||
const { spatials, all_cols: allCols } = datasource;
|
const { spatials, all_cols: allCols } = datasource;
|
||||||
|
@ -416,6 +425,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</Tab>);
|
</Tab>);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderErrors() {
|
renderErrors() {
|
||||||
if (this.state.errors.length > 0) {
|
if (this.state.errors.length > 0) {
|
||||||
return (
|
return (
|
||||||
|
@ -425,6 +435,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMetricCollection() {
|
renderMetricCollection() {
|
||||||
return (
|
return (
|
||||||
<CollectionTable
|
<CollectionTable
|
||||||
|
@ -490,6 +501,7 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
allowDeletes
|
allowDeletes
|
||||||
/>);
|
/>);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const datasource = this.state.datasource;
|
const datasource = this.state.datasource;
|
||||||
return (
|
return (
|
||||||
|
@ -578,6 +590,8 @@ export class DatasourceEditor extends React.PureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DatasourceEditor.defaultProps = defaultProps;
|
DatasourceEditor.defaultProps = defaultProps;
|
||||||
DatasourceEditor.propTypes = propTypes;
|
DatasourceEditor.propTypes = propTypes;
|
||||||
|
|
||||||
export default withToasts(DatasourceEditor);
|
export default withToasts(DatasourceEditor);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Alert, Button, Modal } from 'react-bootstrap';
|
import { Alert, Button, Modal } from 'react-bootstrap';
|
||||||
import Dialog from 'react-bootstrap-dialog';
|
import Dialog from 'react-bootstrap-dialog';
|
||||||
import $ from 'jquery';
|
import { SupersetClient } from '@superset-ui/core';
|
||||||
|
|
||||||
import { t } from '../locales';
|
import { t } from '../locales';
|
||||||
import DatasourceEditor from '../datasource/DatasourceEditor';
|
import DatasourceEditor from '../datasource/DatasourceEditor';
|
||||||
|
@ -40,6 +40,7 @@ class DatasourceModal extends React.PureComponent {
|
||||||
this.onConfirmSave = this.onConfirmSave.bind(this);
|
this.onConfirmSave = this.onConfirmSave.bind(this);
|
||||||
this.setDialogRef = this.setDialogRef.bind(this);
|
this.setDialogRef = this.setDialogRef.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickSave() {
|
onClickSave() {
|
||||||
this.dialog.show({
|
this.dialog.show({
|
||||||
title: t('Confirm save'),
|
title: t('Confirm save'),
|
||||||
|
@ -51,49 +52,48 @@ class DatasourceModal extends React.PureComponent {
|
||||||
body: this.renderSaveDialog(),
|
body: this.renderSaveDialog(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfirmSave() {
|
onConfirmSave() {
|
||||||
const url = '/datasource/save/';
|
SupersetClient.post({
|
||||||
const that = this;
|
endpoint: '/datasource/save/',
|
||||||
$.ajax({
|
postPayload: {
|
||||||
url,
|
data: this.state.datasource,
|
||||||
type: 'POST',
|
|
||||||
data: {
|
|
||||||
data: JSON.stringify(this.state.datasource),
|
|
||||||
},
|
},
|
||||||
success: (data) => {
|
})
|
||||||
|
.then(({ json }) => {
|
||||||
this.props.addSuccessToast(t('The datasource has been saved'));
|
this.props.addSuccessToast(t('The datasource has been saved'));
|
||||||
this.props.onDatasourceSave(data);
|
this.props.onDatasourceSave(json);
|
||||||
this.props.onHide();
|
this.props.onHide();
|
||||||
},
|
})
|
||||||
error(err) {
|
.catch((error) => {
|
||||||
let msg = t('An error has occurred');
|
this.dialog.show({
|
||||||
if (err.responseJSON && err.responseJSON.error) {
|
|
||||||
msg = err.responseJSON.error;
|
|
||||||
}
|
|
||||||
that.dialog.show({
|
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
bsSize: 'medium',
|
bsSize: 'medium',
|
||||||
bsStyle: 'danger',
|
bsStyle: 'danger',
|
||||||
actions: [
|
actions: [
|
||||||
Dialog.DefaultAction('Ok', () => {}, 'btn-danger'),
|
Dialog.DefaultAction('Ok', () => {}, 'btn-danger'),
|
||||||
],
|
],
|
||||||
body: msg,
|
body: error.error || error.statusText || t('An error has occurred'),
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDatasourceChange(datasource, errors) {
|
onDatasourceChange(datasource, errors) {
|
||||||
this.setState({ datasource, errors });
|
this.setState({ datasource, errors });
|
||||||
}
|
}
|
||||||
|
|
||||||
setSearchRef(searchRef) {
|
setSearchRef(searchRef) {
|
||||||
this.searchRef = searchRef;
|
this.searchRef = searchRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDialogRef(ref) {
|
setDialogRef(ref) {
|
||||||
this.dialog = ref;
|
this.dialog = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleShowDatasource() {
|
toggleShowDatasource() {
|
||||||
this.setState({ showDatasource: !this.state.showDatasource });
|
this.setState({ showDatasource: !this.state.showDatasource });
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSaveDialog() {
|
renderSaveDialog() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -111,6 +111,7 @@ class DatasourceModal extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -156,4 +157,5 @@ class DatasourceModal extends React.PureComponent {
|
||||||
|
|
||||||
DatasourceModal.propTypes = propTypes;
|
DatasourceModal.propTypes = propTypes;
|
||||||
DatasourceModal.defaultProps = defaultProps;
|
DatasourceModal.defaultProps = defaultProps;
|
||||||
|
|
||||||
export default withToasts(DatasourceModal);
|
export default withToasts(DatasourceModal);
|
||||||
|
|
|
@ -9,20 +9,16 @@ import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Well,
|
Well,
|
||||||
} from 'react-bootstrap';
|
} from 'react-bootstrap';
|
||||||
import $ from 'jquery';
|
|
||||||
|
|
||||||
import ControlHeader from '../ControlHeader';
|
import ControlHeader from '../ControlHeader';
|
||||||
import { t } from '../../../locales';
|
import { t } from '../../../locales';
|
||||||
import DatasourceModal from '../../../datasource/DatasourceModal';
|
import DatasourceModal from '../../../datasource/DatasourceModal';
|
||||||
import ColumnOption from '../../../components/ColumnOption';
|
import ColumnOption from '../../../components/ColumnOption';
|
||||||
import MetricOption from '../../../components/MetricOption';
|
import MetricOption from '../../../components/MetricOption';
|
||||||
import withToasts from '../../../messageToasts/enhancers/withToasts';
|
|
||||||
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
addDangerToast: PropTypes.func.isRequired,
|
|
||||||
datasource: PropTypes.object.isRequired,
|
datasource: PropTypes.object.isRequired,
|
||||||
onDatasourceSave: PropTypes.func,
|
onDatasourceSave: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
@ -39,70 +35,30 @@ class DatasourceControl extends React.PureComponent {
|
||||||
showEditDatasourceModal: false,
|
showEditDatasourceModal: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
showDatasource: false,
|
showDatasource: false,
|
||||||
|
datasources: null,
|
||||||
};
|
};
|
||||||
this.toggleShowDatasource = this.toggleShowDatasource.bind(this);
|
this.toggleShowDatasource = this.toggleShowDatasource.bind(this);
|
||||||
this.toggleEditDatasourceModal = this.toggleEditDatasourceModal.bind(this);
|
this.toggleEditDatasourceModal = this.toggleEditDatasourceModal.bind(this);
|
||||||
this.setSearchRef = this.setSearchRef.bind(this);
|
|
||||||
this.selectDatasource = this.selectDatasource.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(vizType) {
|
onChange(vizType) {
|
||||||
this.props.onChange(vizType);
|
this.props.onChange(vizType);
|
||||||
this.setState({ showModal: false });
|
this.setState({ showModal: false });
|
||||||
}
|
}
|
||||||
onEnterModal() {
|
|
||||||
if (this.searchRef) {
|
|
||||||
this.searchRef.focus();
|
|
||||||
}
|
|
||||||
const url = '/superset/datasources/';
|
|
||||||
const that = this;
|
|
||||||
if (!this.state.datasources) {
|
|
||||||
$.ajax({
|
|
||||||
type: 'GET',
|
|
||||||
url,
|
|
||||||
success: (data) => {
|
|
||||||
const datasources = data.map(ds => ({
|
|
||||||
rawName: ds.name,
|
|
||||||
connection: ds.connection,
|
|
||||||
schema: ds.schema,
|
|
||||||
name: (
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
onClick={this.selectDatasource.bind(this, ds.uid)}
|
|
||||||
className="datasource-link"
|
|
||||||
>
|
|
||||||
{ds.name}
|
|
||||||
</a>
|
|
||||||
),
|
|
||||||
type: ds.type,
|
|
||||||
}));
|
|
||||||
|
|
||||||
that.setState({ loading: false, datasources });
|
|
||||||
},
|
|
||||||
error() {
|
|
||||||
that.setState({ loading: false });
|
|
||||||
this.props.addDangerToast(t('Something went wrong while fetching the datasource list'));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setSearchRef(searchRef) {
|
|
||||||
this.searchRef = searchRef;
|
|
||||||
}
|
|
||||||
toggleShowDatasource() {
|
toggleShowDatasource() {
|
||||||
this.setState({ showDatasource: !this.state.showDatasource });
|
this.setState(({ showDatasource }) => ({ showDatasource: !showDatasource }));
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleModal() {
|
toggleModal() {
|
||||||
this.setState({ showModal: !this.state.showModal });
|
this.setState(({ showModal }) => ({ showModal: !showModal }));
|
||||||
}
|
|
||||||
selectDatasource(datasourceId) {
|
|
||||||
this.setState({ showModal: false });
|
|
||||||
this.props.onChange(datasourceId);
|
|
||||||
}
|
}
|
||||||
toggleEditDatasourceModal() {
|
toggleEditDatasourceModal() {
|
||||||
this.setState({ showEditDatasourceModal: !this.state.showEditDatasourceModal });
|
this.setState(({ showEditDatasourceModal }) => ({
|
||||||
}
|
showEditDatasourceModal: !showEditDatasourceModal,
|
||||||
renderModal() {
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDatasource() {
|
renderDatasource() {
|
||||||
const datasource = this.props.datasource;
|
const datasource = this.props.datasource;
|
||||||
return (
|
return (
|
||||||
|
@ -136,6 +92,7 @@ class DatasourceControl extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -193,4 +150,4 @@ class DatasourceControl extends React.PureComponent {
|
||||||
DatasourceControl.propTypes = propTypes;
|
DatasourceControl.propTypes = propTypes;
|
||||||
DatasourceControl.defaultProps = defaultProps;
|
DatasourceControl.defaultProps = defaultProps;
|
||||||
|
|
||||||
export default withToasts(DatasourceControl);
|
export default DatasourceControl;
|
||||||
|
|
Loading…
Reference in New Issue