diff --git a/superset/assets/javascripts/components/ColumnOption.jsx b/superset/assets/javascripts/components/ColumnOption.jsx index c150937a0b2d1..f579126b8d6ee 100644 --- a/superset/assets/javascripts/components/ColumnOption.jsx +++ b/superset/assets/javascripts/components/ColumnOption.jsx @@ -5,9 +5,13 @@ import InfoTooltipWithTrigger from './InfoTooltipWithTrigger'; const propTypes = { column: PropTypes.object.isRequired, + showType: PropTypes.bool, +}; +const defaultProps = { + showType: false, }; -export default function ColumnOption({ column }) { +export default function ColumnOption({ column, showType }) { return ( @@ -29,6 +33,10 @@ export default function ColumnOption({ column }) { label={`expr-${column.column_name}`} /> } + {showType && + {column.type} + } ); } ColumnOption.propTypes = propTypes; +ColumnOption.defaultProps = defaultProps; diff --git a/superset/assets/javascripts/explore/components/controls/DatasourceControl.jsx b/superset/assets/javascripts/explore/components/controls/DatasourceControl.jsx index eb7a63367cf0f..e63c80708946a 100644 --- a/superset/assets/javascripts/explore/components/controls/DatasourceControl.jsx +++ b/superset/assets/javascripts/explore/components/controls/DatasourceControl.jsx @@ -2,10 +2,15 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Table } from 'reactable'; -import { Label, FormControl, Modal, OverlayTrigger, Tooltip } from 'react-bootstrap'; +import { + Row, Col, Collapse, Label, FormControl, Modal, + OverlayTrigger, Tooltip, Well, +} from 'react-bootstrap'; import ControlHeader from '../ControlHeader'; import { t } from '../../../locales'; +import ColumnOption from '../../../components/ColumnOption'; +import MetricOption from '../../../components/MetricOption'; const propTypes = { description: PropTypes.string, @@ -27,11 +32,14 @@ export default class DatasourceControl extends React.PureComponent { showModal: false, filter: '', loading: true, + showDatasource: false, }; + this.toggleShowDatasource = this.toggleShowDatasource.bind(this); + this.onChange = this.onChange.bind(this); + this.onEnterModal = this.onEnterModal.bind(this); this.toggleModal = this.toggleModal.bind(this); this.changeSearch = this.changeSearch.bind(this); - this.setSearchRef = this.setSearchRef.bind(this); - this.onEnterModal = this.onEnterModal.bind(this); + this.selectDatasource = this.selectDatasource.bind(this); } onChange(vizType) { this.props.onChange(vizType); @@ -75,6 +83,9 @@ export default class DatasourceControl extends React.PureComponent { setSearchRef(searchRef) { this.searchRef = searchRef; } + toggleShowDatasource() { + this.setState({ showDatasource: !this.state.showDatasource }); + } toggleModal() { this.setState({ showModal: !this.state.showModal }); } @@ -85,6 +96,79 @@ export default class DatasourceControl extends React.PureComponent { this.setState({ showModal: false }); this.props.onChange(datasourceId); } + renderModal() { + return ( + + + {t('Select a datasource')} + + +
+ { this.setSearchRef(ref); }} + type="text" + bsSize="sm" + value={this.state.filter} + placeholder={t('Search / Filter')} + onChange={this.changeSearch} + /> +
+ {this.state.loading && + Loading... + } + {this.state.datasources && + + } + + ); + } + renderDatasource() { + const datasource = this.props.datasource; + return ( +
+ +
+ + {` ${datasource.database.name} `} +
+ +
+ Columns + {datasource.columns.map(col => ( +
+ ))} + +
+ Metrics + {datasource.metrics.map(m => ( +
+ ))} + + + + ); + } render() { return (
@@ -108,51 +192,28 @@ export default class DatasourceControl extends React.PureComponent { } > - + - + {t('Show datasource configuration')} + + } > - - {t('Select a datasource')} - - -
- { this.setSearchRef(ref); }} - type="text" - bsSize="sm" - value={this.state.filter} - placeholder={t('Search / Filter')} - onChange={this.changeSearch} - /> -
- {this.state.loading && - Loading... - } - {this.state.datasources && -
- } - - + + + + + + {this.renderDatasource()} + + {this.renderModal()} ); } } diff --git a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx index c46ded004a230..d206829cd726f 100644 --- a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx @@ -15,6 +15,12 @@ const defaultProps = { type: 'table', uid: '1__table', id: 1, + columns: [], + metrics: [], + database: { + backend: 'mysql', + name: 'main', + }, }, onChange: sinon.spy(), }; diff --git a/superset/assets/stylesheets/superset.less b/superset/assets/stylesheets/superset.less index ae0be2cd64ee5..14c7519bcab94 100644 --- a/superset/assets/stylesheets/superset.less +++ b/superset/assets/stylesheets/superset.less @@ -252,6 +252,9 @@ table.table-no-hover tr:hover { .m-t-10 { margin-top: 10px; } +.m-b-10 { + margin-bottom: 10px; +} .m-l-5 { margin-left: 5px; } diff --git a/superset/connectors/base/models.py b/superset/connectors/base/models.py index 9bead749ddd1a..2057ea8aa9f84 100644 --- a/superset/connectors/base/models.py +++ b/superset/connectors/base/models.py @@ -157,6 +157,7 @@ def data(self): return { 'all_cols': utils.choicify(self.column_names), 'column_formats': self.column_formats, + 'database': self.database.data, # pylint: disable=no-member 'edit_url': self.url, 'filter_select': self.filter_select_enabled, 'filterable_cols': utils.choicify(self.filterable_column_names), @@ -256,7 +257,7 @@ def expression(self): def data(self): attrs = ( 'column_name', 'verbose_name', 'description', 'expression', - 'filterable', 'groupby', 'is_dttm') + 'filterable', 'groupby', 'is_dttm', 'type') return {s: getattr(self, s) for s in attrs} diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index a1d9ec0944c35..45d5d25913218 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -91,6 +91,13 @@ class DruidCluster(Model, AuditMixinNullable, ImportMixin): def __repr__(self): return self.verbose_name if self.verbose_name else self.cluster_name + @property + def data(self): + return { + 'name': self.cluster_name, + 'backend': 'druid', + } + def get_pydruid_client(self): cli = PyDruid( 'http://{0}:{1}/'.format(self.broker_host, self.broker_port), diff --git a/superset/models/core.py b/superset/models/core.py index 396db2dc32329..f2ca42bb13a7c 100644 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -581,6 +581,13 @@ def __repr__(self): def name(self): return self.verbose_name if self.verbose_name else self.database_name + @property + def data(self): + return { + 'name': self.database_name, + 'backend': self.backend, + } + @property def unique_name(self): return self.database_name