Added access check + Druid in endpoint (#1224)
* Explore control panel - Chart control, TimeFilter, GroupBy, Filters (#1205) * create structure for new forked explore view (#1099) * create structure for new forked explore view * update component name * add bootstrap data pattern * remove console.log * Associate version to entry files (#1060) * Associate version to entry files * Modified path joins for configs * Made changes based on comments * Created store and reducers (#1108) * Created store and reducers * Added spec * Modifications based on comments * Explore control panel components: Chart control, Time filter, SQL, GroupBy and Filters * Modifications based on comments * Added access check + Druid in endpoint * pull grains to constants * Switch explore.html to old version
This commit is contained in:
parent
a92190c3ae
commit
8ab5e5015a
|
|
@ -29,6 +29,7 @@ export const CHANGE_FILTER_OP = 'CHANGE_FILTER_OP';
|
|||
export const CHANGE_FILTER_VALUE = 'CHANGE_FILTER_VALUE';
|
||||
export const RESET_FORM_DATA = 'RESET_FORM_DATA';
|
||||
export const CLEAR_ALL_OPTS = 'CLEAR_ALL_OPTS';
|
||||
export const SET_DATASOURCE_CLASS = 'SET_DATASOURCE_CLASS';
|
||||
|
||||
export function setTimeColumnOpts(timeColumnOpts) {
|
||||
return { type: SET_TIME_COLUMN_OPTS, timeColumnOpts };
|
||||
|
|
@ -59,6 +60,10 @@ export function clearAllOpts() {
|
|||
return { type: CLEAR_ALL_OPTS };
|
||||
}
|
||||
|
||||
export function setDatasourceClass(datasourceClass) {
|
||||
return { type: SET_DATASOURCE_CLASS, datasourceClass };
|
||||
}
|
||||
|
||||
export function setFormOpts(datasourceId, datasourceType) {
|
||||
return function (dispatch) {
|
||||
const timeColumnOpts = [];
|
||||
|
|
@ -73,7 +78,7 @@ export function setFormOpts(datasourceId, datasourceType) {
|
|||
|
||||
$.get(url, (data, status) => {
|
||||
if (status === 'success') {
|
||||
data.dttm_cols.forEach((d) => {
|
||||
data.time_columns.forEach((d) => {
|
||||
if (d) timeColumnOpts.push({ value: d, label: d });
|
||||
});
|
||||
data.groupby_cols.forEach((d) => {
|
||||
|
|
@ -89,6 +94,7 @@ export function setFormOpts(datasourceId, datasourceType) {
|
|||
if (d) timeGrainOpts.push({ value: d, label: d });
|
||||
});
|
||||
// Repopulate options for controls
|
||||
dispatch(setDatasourceClass(data.datasource_class));
|
||||
dispatch(setTimeColumnOpts(timeColumnOpts));
|
||||
dispatch(setTimeGrainOpts(timeGrainOpts));
|
||||
dispatch(setGroupByColumnOpts(groupByColumnOpts));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { sinceOptions, untilOptions } from '../constants';
|
|||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
datasourceClass: React.PropTypes.string,
|
||||
timeColumnOpts: React.PropTypes.array,
|
||||
timeColumn: React.PropTypes.string,
|
||||
timeGrainOpts: React.PropTypes.array,
|
||||
|
|
@ -42,16 +43,20 @@ class TimeFilter extends React.Component {
|
|||
this.props.actions.setUntil(val);
|
||||
}
|
||||
render() {
|
||||
const timeColumnPlaceHolder =
|
||||
(this.props.datasourceClass === 'SqlaTable') ? 'Time Column' : 'Time Granularity';
|
||||
const timeGrainPlaceHolder =
|
||||
(this.props.datasourceClass === 'SqlaTable') ? 'Time Grain' : 'Origin';
|
||||
return (
|
||||
<div className="panel space-1">
|
||||
<div className="panel-header">Time Filter</div>
|
||||
<div className="panel-body">
|
||||
<div className="row">
|
||||
<h5 className="section-heading">Time Column & Grain</h5>
|
||||
<h5 className="section-heading">Time Column & Grains</h5>
|
||||
<Select
|
||||
className="col-sm-6"
|
||||
name="select-time-column"
|
||||
placeholder="Select a time column"
|
||||
placeholder={`Select a ${timeColumnPlaceHolder}`}
|
||||
options={this.props.timeColumnOpts}
|
||||
value={this.props.timeColumn}
|
||||
autosize={false}
|
||||
|
|
@ -60,7 +65,7 @@ class TimeFilter extends React.Component {
|
|||
<Select
|
||||
className="col-sm-6"
|
||||
name="select-time-grain"
|
||||
placeholder="Select a time grain"
|
||||
placeholder={`Select a ${timeGrainPlaceHolder}`}
|
||||
options={this.props.timeGrainOpts}
|
||||
value={this.props.timeGrain}
|
||||
autosize={false}
|
||||
|
|
@ -99,6 +104,7 @@ TimeFilter.defaultProps = defaultProps;
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
datasourceClass: state.datasourceClass,
|
||||
timeColumnOpts: state.timeColumnOpts,
|
||||
timeColumn: state.timeColumn,
|
||||
timeGrainOpts: state.timeGrainOpts,
|
||||
|
|
|
|||
|
|
@ -17,12 +17,13 @@ const bootstrappedState = Object.assign(initialState, {
|
|||
datasources: bootstrapData.datasources,
|
||||
datasourceId: parseInt(bootstrapData.datasource_id, 10),
|
||||
datasourceType: bootstrapData.datasource_type,
|
||||
datasourceClass: bootstrapData.datasource_class,
|
||||
sliceName: bootstrapData.viz.form_data.slice_name,
|
||||
sliceId: bootstrapData.viz.form_data.slice_id,
|
||||
vizType: bootstrapData.viz.form_data.viz_type,
|
||||
timeColumn: bootstrapData.viz.form_data.granularity_sqla,
|
||||
timeGrain: bootstrapData.viz.form_data.time_grain_sqla,
|
||||
metrics: [bootstrapData.viz.form_data.metric].map((m) => ({ value: m, label: m })),
|
||||
metrics: [bootstrapData.viz.form_data.metrics].map((m) => ({ value: m, label: m })),
|
||||
since: bootstrapData.viz.form_data.since,
|
||||
until: bootstrapData.viz.form_data.until,
|
||||
havingClause: bootstrapData.viz.form_data.having,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ export const exploreReducer = function (state, action) {
|
|||
[actions.CLEAR_ALL_OPTS]() {
|
||||
return Object.assign({}, state, defaultOpts);
|
||||
},
|
||||
[actions.SET_DATASOURCE_CLASS]() {
|
||||
return Object.assign({}, state, { datasourceClass: action.datasourceClass });
|
||||
},
|
||||
};
|
||||
if (action.type in actionHandlers) {
|
||||
return actionHandlers[action.type]();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ export const initialState = {
|
|||
datasources: null,
|
||||
datasourceId: null,
|
||||
datasourceType: null,
|
||||
datasourceClass: null,
|
||||
vizType: null,
|
||||
timeColumnOpts: [],
|
||||
timeColumn: null,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ config = app.config
|
|||
log_this = models.Log.log_this
|
||||
can_access = utils.can_access
|
||||
QueryStatus = models.QueryStatus
|
||||
DRUID_TIME_GRAINS = [
|
||||
'all', '5 seconds', '30 seconds', '1 minute',
|
||||
'5 minutes', '1 hour', '6 hour', '1 day', '7 days'
|
||||
]
|
||||
|
||||
|
||||
class BaseCaravelView(BaseView):
|
||||
|
|
@ -1297,6 +1301,7 @@ class Caravel(BaseCaravelView):
|
|||
"datasources": [(d.id, d.full_name) for d in datasources],
|
||||
"datasource_id": datasource_id,
|
||||
"datasource_type": datasource_type,
|
||||
"datasource_class": datasource_class.__name__,
|
||||
"user_id": g.user.get_id() if g.user else None,
|
||||
"viz": json.loads(viz_obj.get_json())
|
||||
}
|
||||
|
|
@ -1942,8 +1947,6 @@ class Caravel(BaseCaravelView):
|
|||
@expose("/fetch_datasource_metadata")
|
||||
@log_this
|
||||
def fetch_datasource_metadata(self):
|
||||
# TODO: check permissions
|
||||
# TODO: check if datasource exits
|
||||
session = db.session
|
||||
datasource_type = request.args.get('datasource_type')
|
||||
datasource_class = SourceRegistry.sources[datasource_type]
|
||||
|
|
@ -1952,17 +1955,34 @@ class Caravel(BaseCaravelView):
|
|||
.filter_by(id=request.args.get('datasource_id'))
|
||||
.first()
|
||||
)
|
||||
# SUPPORT DRUID
|
||||
# TODO: move this logic to the model (maybe)
|
||||
datasource_grains = datasource.database.grains()
|
||||
grain_names = [str(grain.name) for grain in datasource_grains]
|
||||
|
||||
# Check if datasource exists
|
||||
if not datasource:
|
||||
return json_error_response(DATASOURCE_MISSING_ERR)
|
||||
# Check permission for datasource
|
||||
if not self.datasource_access(datasource):
|
||||
return json_error_response(DATASOURCE_ACCESS_ERR)
|
||||
|
||||
time_columns = []
|
||||
grains_choices = []
|
||||
datasource_class_name = datasource_class.__name__
|
||||
if datasource_class_name == 'SqlaTable':
|
||||
time_columns = datasource.dttm_cols
|
||||
grains = datasource.database.grains()
|
||||
grains_choices = [grain.name for grain in grains]
|
||||
elif datasource_class_name == 'DruidDatasource':
|
||||
time_columns = DRUID_TIME_GRAINS
|
||||
grains_choices = ['now']
|
||||
|
||||
form_data = {
|
||||
"dttm_cols": datasource.dttm_cols,
|
||||
"time_grains": grain_names,
|
||||
"groupby_cols": datasource.groupby_column_names,
|
||||
"metrics": datasource.metrics_combo,
|
||||
"filter_cols": datasource.filterable_column_names,
|
||||
}
|
||||
"datasource_class": datasource_class_name,
|
||||
"time_columns": time_columns,
|
||||
"time_grains": grains_choices,
|
||||
"groupby_cols": datasource.groupby_column_names,
|
||||
"metrics": datasource.metrics_combo,
|
||||
"filter_cols": datasource.filterable_column_names,
|
||||
}
|
||||
|
||||
return Response(
|
||||
json.dumps(form_data), mimetype="application/json")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue