diff --git a/caravel/assets/javascripts/explorev2/actions/exploreActions.js b/caravel/assets/javascripts/explorev2/actions/exploreActions.js
index 32268f7d03..6468c6ac39 100644
--- a/caravel/assets/javascripts/explorev2/actions/exploreActions.js
+++ b/caravel/assets/javascripts/explorev2/actions/exploreActions.js
@@ -11,11 +11,11 @@ export const SET_GROUPBY_COLUMNS = 'SET_GROUPBY_COLUMNS';
export const SET_GROUPBY_COLUMN_OPTS = 'SET_GROUPBY_COLUMN_OPTS';
export const SET_METRICS = 'SET_METRICS';
export const SET_METRICS_OPTS = 'SET_METRICS_OPTS';
-export const ADD_COLUMN = 'ADD_COLUMN';
-export const REMOVE_COLUMN = 'REMOVE_COLUMN';
-export const ADD_ORDERING = 'ADD_ORDERING';
-export const REMOVE_ORDERING = 'REMOVE_ORDERING';
-export const SET_TIME_STAMP = 'SET_TIME_STAMP';
+export const SET_COLUMN_OPTS = 'SET_COLUMN_OPTS';
+export const SET_NOT_GROUPBY_COLUMNS = 'SET_NOT_GROUPBY_COLUMNS';
+export const SET_ORDERING_OPTS = 'SET_ORDERING_OPTS';
+export const SET_ORDERINGS = 'SET_ORDERINGS';
+export const SET_TIME_STAMP_FORMAT = 'SET_TIME_STAMP_FORMAT';
export const SET_ROW_LIMIT = 'SET_ROW_LIMIT';
export const TOGGLE_SEARCHBOX = 'TOGGLE_SEARCHBOX';
export const SET_FILTER_COLUMN_OPTS = 'SET_FILTER_COLUMN_OPTS';
@@ -47,6 +47,14 @@ export function setMetricsOpts(metricsOpts) {
return { type: SET_METRICS_OPTS, metricsOpts };
}
+export function setColumnOpts(columnOpts) {
+ return { type: SET_COLUMN_OPTS, columnOpts };
+}
+
+export function setOrderingOpts(orderingOpts) {
+ return { type: SET_ORDERING_OPTS, orderingOpts };
+}
+
export function setFilterColumnOpts(filterColumnOpts) {
return { type: SET_FILTER_COLUMN_OPTS, filterColumnOpts };
}
@@ -71,6 +79,8 @@ export function setFormOpts(datasourceId, datasourceType) {
const metricsOpts = [];
const filterColumnOpts = [];
const timeGrainOpts = [];
+ const columnOpts = [];
+ const orderingOpts = [];
if (datasourceId) {
const params = [`datasource_id=${datasourceId}`, `datasource_type=${datasourceType}`];
@@ -93,12 +103,21 @@ export function setFormOpts(datasourceId, datasourceType) {
data.time_grains.forEach((d) => {
if (d) timeGrainOpts.push({ value: d, label: d });
});
+ data.columns.forEach((d) => {
+ if (d) columnOpts.push({ value: d, label: d });
+ });
+ data.ordering_cols.forEach((d) => {
+ if (d) orderingOpts.push({ value: d, label: d });
+ });
+
// Repopulate options for controls
dispatch(setTimeColumnOpts(timeColumnOpts));
dispatch(setTimeGrainOpts(timeGrainOpts));
dispatch(setGroupByColumnOpts(groupByColumnOpts));
dispatch(setMetricsOpts(metricsOpts));
dispatch(setFilterColumnOpts(filterColumnOpts));
+ dispatch(setColumnOpts(columnOpts));
+ dispatch(setOrderingOpts(orderingOpts));
}
});
} else {
@@ -140,24 +159,16 @@ export function setMetrics(metrics) {
return { type: SET_METRICS, metrics };
}
-export function addColumn(column) {
- return { type: ADD_COLUMN, column };
+export function setNotGroupByColumns(columns) {
+ return { type: SET_NOT_GROUPBY_COLUMNS, columns };
}
-export function removeColumn(column) {
- return { type: REMOVE_COLUMN, column };
+export function setOrderings(orderings) {
+ return { type: SET_ORDERINGS, orderings };
}
-export function addOrdering(ordering) {
- return { type: ADD_ORDERING, ordering };
-}
-
-export function removeOrdering(ordering) {
- return { type: REMOVE_ORDERING, ordering };
-}
-
-export function setTimeStamp(timeStampFormat) {
- return { type: SET_TIME_STAMP, timeStampFormat };
+export function setTimeStampFormat(timeStampFormat) {
+ return { type: SET_TIME_STAMP_FORMAT, timeStampFormat };
}
export function setRowLimit(rowLimit) {
diff --git a/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx b/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
index c3f70e9532..a3a0ccbcd2 100644
--- a/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
+++ b/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
@@ -1,20 +1,36 @@
import React from 'react';
+import { connect } from 'react-redux';
import { Panel } from 'react-bootstrap';
-import TimeFilter from './TimeFilter';
-import ChartControl from './ChartControl';
-import GroupBy from './GroupBy';
-import SqlClause from './SqlClause';
-import Filters from './Filters';
+import { DefaultControls, VIZ_CONTROL_MAPPING } from '../constants';
-const ControlPanelsContainer = function () {
+const propTypes = {
+ vizType: React.PropTypes.string,
+};
+
+const defaultProps = {
+ vizType: null,
+};
+
+function ControlPanelsContainer(props) {
return (
-
-
-
-
-
+ {DefaultControls}
+ {VIZ_CONTROL_MAPPING[props.vizType]}
);
-};
-export default ControlPanelsContainer;
+}
+
+ControlPanelsContainer.propTypes = propTypes;
+ControlPanelsContainer.defaultProps = defaultProps;
+
+function mapStateToProps(state) {
+ return {
+ vizType: state.vizType,
+ };
+}
+
+function mapDispatchToProps() {
+ return {};
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ControlPanelsContainer);
diff --git a/caravel/assets/javascripts/explorev2/components/Filters.jsx b/caravel/assets/javascripts/explorev2/components/Filters.jsx
index 49e384157f..13e465c610 100644
--- a/caravel/assets/javascripts/explorev2/components/Filters.jsx
+++ b/caravel/assets/javascripts/explorev2/components/Filters.jsx
@@ -109,7 +109,6 @@ class Filters extends React.Component {
}
Filters.propTypes = propTypes;
-
Filters.defaultProps = defaultProps;
function mapStateToProps(state) {
diff --git a/caravel/assets/javascripts/explorev2/components/GroupBy.jsx b/caravel/assets/javascripts/explorev2/components/GroupBy.jsx
index cbf10fdfe5..2d7756c8df 100644
--- a/caravel/assets/javascripts/explorev2/components/GroupBy.jsx
+++ b/caravel/assets/javascripts/explorev2/components/GroupBy.jsx
@@ -20,11 +20,11 @@ const defaultProps = {
};
class GroupBy extends React.Component {
- changeColumns(groupByColumnOpts) {
- this.props.actions.setGroupByColumns(groupByColumnOpts);
+ changeColumns(groupByColumns) {
+ this.props.actions.setGroupByColumns(groupByColumns);
}
- changeMetrics(metricsOpts) {
- this.props.actions.setMetrics(metricsOpts);
+ changeMetrics(metrics) {
+ this.props.actions.setMetrics(metrics);
}
render() {
return (
diff --git a/caravel/assets/javascripts/explorev2/components/NotGroupBy.jsx b/caravel/assets/javascripts/explorev2/components/NotGroupBy.jsx
new file mode 100644
index 0000000000..ece64525e2
--- /dev/null
+++ b/caravel/assets/javascripts/explorev2/components/NotGroupBy.jsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import Select from 'react-select';
+import { bindActionCreators } from 'redux';
+import * as actions from '../actions/exploreActions';
+import { connect } from 'react-redux';
+
+const propTypes = {
+ actions: React.PropTypes.object,
+ columnOpts: React.PropTypes.array,
+ columns: React.PropTypes.array,
+ orderingOpts: React.PropTypes.array,
+ orderings: React.PropTypes.array,
+};
+
+const defaultProps = {
+ columnOpts: [],
+ columns: [],
+ orderingOpts: [],
+ orderings: [],
+};
+
+class NotGroupBy extends React.Component {
+ changeColumns(columns) {
+ this.props.actions.setNotGroupByColumns(columns);
+ }
+ changeOrderings(orderings) {
+ this.props.actions.setOrderings(orderings);
+ }
+ render() {
+ return (
+
+
Not GroupBy
+
+
+
Columns
+
+
+
+
Orderings
+
+
+
+
+ );
+ }
+}
+
+NotGroupBy.propTypes = propTypes;
+NotGroupBy.defaultProps = defaultProps;
+
+function mapStateToProps(state) {
+ return {
+ columnOpts: state.columnOpts,
+ columns: state.columns,
+ orderingOpts: state.orderingOpts,
+ orderings: state.orderings,
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(actions, dispatch),
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(NotGroupBy);
diff --git a/caravel/assets/javascripts/explorev2/components/Options.jsx b/caravel/assets/javascripts/explorev2/components/Options.jsx
new file mode 100644
index 0000000000..687c197fb5
--- /dev/null
+++ b/caravel/assets/javascripts/explorev2/components/Options.jsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import Select from 'react-select';
+import { bindActionCreators } from 'redux';
+import * as actions from '../actions/exploreActions';
+import { connect } from 'react-redux';
+import { timestampOptions, rowLimitOptions } from '../constants';
+
+const propTypes = {
+ actions: React.PropTypes.object,
+ timeStampFormat: React.PropTypes.string,
+ rowLimit: React.PropTypes.number,
+};
+
+const defaultProps = {
+ timeStampFormat: null,
+ rowLimit: null,
+};
+
+class Options extends React.Component {
+ changeTimeStampFormat(timeStampFormat) {
+ const val = (timeStampFormat) ? timeStampFormat.value : null;
+ this.props.actions.setTimeStampFormat(val);
+ }
+ changeRowLimit(rowLimit) {
+ this.props.actions.setRowLimit(rowLimit);
+ }
+ render() {
+ return (
+
+
Options
+
+
+
Table Timestamp Format
+
+
+
Row Limit
+
+
+
+ );
+ }
+}
+
+Options.propTypes = propTypes;
+Options.defaultProps = defaultProps;
+
+function mapStateToProps(state) {
+ return {
+ timeStampFormat: state.timeStampFormat,
+ rowLimit: state.rowLimit,
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(actions, dispatch),
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Options);
diff --git a/caravel/assets/javascripts/explorev2/constants.js b/caravel/assets/javascripts/explorev2/constants.js
index 2415eaa43e..384abe30be 100644
--- a/caravel/assets/javascripts/explorev2/constants.js
+++ b/caravel/assets/javascripts/explorev2/constants.js
@@ -1,3 +1,12 @@
+import React from 'react';
+import TimeFilter from './components/TimeFilter';
+import ChartControl from './components/ChartControl';
+import GroupBy from './components/GroupBy';
+import SqlClause from './components/SqlClause';
+import Filters from './components/Filters';
+import NotGroupBy from './components/NotGroupBy';
+import Options from './components/Options';
+
export const VIZ_TYPES = [
{ value: 'dist_bar', label: 'Distribution - Bar Chart', requiresTime: false },
{ value: 'pie', label: 'Pie Chart', requiresTime: false },
@@ -33,3 +42,35 @@ export const sinceOptions = ['1 hour ago', '12 hours ago', '1 day ago',
'7 days ago', '28 days ago', '90 days ago', '1 year ago'];
export const untilOptions = ['now', '1 day ago', '7 days ago',
'28 days ago', '90 days ago', '1 year ago'];
+
+export const timestampOptions = [
+ ['smart_date', 'Adaptative formating'],
+ ['%m/%d/%Y', '"%m/%d/%Y" | 01/14/2019'],
+ ['%Y-%m-%d', '"%Y-%m-%d" | 2019-01-14'],
+ ['%Y-%m-%d %H:%M:%S',
+ '"%Y-%m-%d %H:%M:%S" | 2019-01-14 01:32:10'],
+ ['%H:%M:%S', '"%H:%M:%S" | 01:32:10'],
+];
+
+export const rowLimitOptions = [10, 50, 100, 250, 500, 1000, 5000, 10000, 50000];
+
+export const DefaultControls = (
+
+
+
+
+
+
+
+);
+
+export const TableVizControls = (
+
+
+
+
+);
+
+export const VIZ_CONTROL_MAPPING = {
+ table: TableVizControls,
+};
diff --git a/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js b/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
index da650d120a..9e5d9d94f4 100644
--- a/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
+++ b/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
@@ -40,31 +40,19 @@ export const exploreReducer = function (state, action) {
[actions.SET_METRICS]() {
return Object.assign({}, state, { metrics: action.metrics });
},
- [actions.ADD_COLUMN]() {
- return Object.assign({}, state, { columns: [...state.columns, action.column] });
+ [actions.SET_COLUMN_OPTS]() {
+ return Object.assign({}, state, { columnOpts: action.columnOpts });
},
- [actions.REMOVE_COLUMN]() {
- const newColumns = [];
- state.columns.forEach((c) => {
- if (c !== action.column) {
- newColumns.push(c);
- }
- });
- return Object.assign({}, state, { columns: newColumns });
+ [actions.SET_NOT_GROUPBY_COLUMNS]() {
+ return Object.assign({}, state, { columns: action.columns });
},
- [actions.ADD_ORDERING]() {
- return Object.assign({}, state, { orderings: [...state.orderings, action.ordering] });
+ [actions.SET_ORDERING_OPTS]() {
+ return Object.assign({}, state, { orderingOpts: action.orderingOpts });
},
- [actions.REMOVE_ORDERING]() {
- const newOrderings = [];
- state.orderings.forEach((o) => {
- if (o !== action.ordering) {
- newOrderings.push(o);
- }
- });
- return Object.assign({}, state, { orderings: newOrderings });
+ [actions.SET_ORDERINGS]() {
+ return Object.assign({}, state, { orderings: action.orderings });
},
- [actions.SET_TIME_STAMP]() {
+ [actions.SET_TIME_STAMP_FORMAT]() {
return Object.assign({}, state, { timeStampFormat: action.timeStampFormat });
},
[actions.SET_ROW_LIMIT]() {
diff --git a/caravel/assets/javascripts/explorev2/stores/store.js b/caravel/assets/javascripts/explorev2/stores/store.js
index 80d1bd7296..236013c1da 100644
--- a/caravel/assets/javascripts/explorev2/stores/store.js
+++ b/caravel/assets/javascripts/explorev2/stores/store.js
@@ -13,10 +13,12 @@ export const initialState = {
groupByColumns: [],
metricsOpts: [],
metrics: [],
+ columnOpts: [],
columns: [],
+ orderingOpts: [],
orderings: [],
- timeStampFormat: null,
- rowLimit: null,
+ timeStampFormat: 'smart_date',
+ rowLimit: 50000,
searchBox: false,
whereClause: '',
havingClause: '',
@@ -35,8 +37,8 @@ export const defaultFormData = {
metrics: [],
columns: [],
orderings: [],
- timeStampFormat: null,
- rowLimit: null,
+ timeStampFormat: 'smart_date',
+ rowLimit: 50000,
searchBox: false,
whereClause: '',
havingClause: '',
@@ -49,4 +51,6 @@ export const defaultOpts = {
groupByColumnOpts: [],
metricsOpts: [],
filterColumnOpts: [],
+ columnOpts: [],
+ orderingOpts: [],
};
diff --git a/caravel/assets/spec/javascripts/explore/components/actions_spec.js b/caravel/assets/spec/javascripts/explore/components/actions_spec.js
index 06cb77e4d9..6c18b2a0ee 100644
--- a/caravel/assets/spec/javascripts/explore/components/actions_spec.js
+++ b/caravel/assets/spec/javascripts/explore/components/actions_spec.js
@@ -16,34 +16,20 @@ describe('reducers', () => {
expect(newState.vizType).to.equal('bar');
});
- it('should return new state with added column', () => {
- const newColumn = 'col';
- const newState = exploreReducer(initialState, actions.addColumn(newColumn));
- expect(newState.columns).to.deep.equal([newColumn]);
+ it('should return new state with not groupby columns', () => {
+ const newColumn = ['col'];
+ const newState = exploreReducer(initialState, actions.setNotGroupByColumns(newColumn));
+ expect(newState.columns).to.deep.equal(['col']);
});
- it('should return new state with removed column', () => {
- const testState = { initialState, columns: ['col1', 'col2'] };
- const remColumn = 'col1';
- const newState = exploreReducer(testState, actions.removeColumn(remColumn));
- expect(newState.columns).to.deep.equal(['col2']);
- });
-
- it('should return new state with added ordering', () => {
- const newOrdering = 'ord';
- const newState = exploreReducer(initialState, actions.addOrdering(newOrdering));
+ it('should return new state with orderings', () => {
+ const newOrdering = ['ord'];
+ const newState = exploreReducer(initialState, actions.setOrderings(newOrdering));
expect(newState.orderings).to.deep.equal(['ord']);
});
- it('should return new state with removed ordering', () => {
- const testState = { initialState, orderings: ['ord1', 'ord2'] };
- const remOrdering = 'ord1';
- const newState = exploreReducer(testState, actions.removeOrdering(remOrdering));
- expect(newState.orderings).to.deep.equal(['ord2']);
- });
-
it('should return new state with time stamp', () => {
- const newState = exploreReducer(initialState, actions.setTimeStamp(1));
+ const newState = exploreReducer(initialState, actions.setTimeStampFormat(1));
expect(newState.timeStampFormat).to.equal(1);
});
diff --git a/caravel/views.py b/caravel/views.py
index 0124f788f6..c9574d2980 100755
--- a/caravel/views.py
+++ b/caravel/views.py
@@ -1958,10 +1958,16 @@ class Caravel(BaseCaravelView):
if not self.datasource_access(datasource):
return json_error_response(DATASOURCE_ACCESS_ERR)
+ order_by_choices = []
+ for s in sorted(datasource.num_cols):
+ order_by_choices.append(s + ' [asc]')
+ order_by_choices.append(s + ' [desc]')
column_opts = {
"groupby_cols": datasource.groupby_column_names,
"metrics": datasource.metrics_combo,
- "filter_cols": datasource.filterable_column_names
+ "filter_cols": datasource.filterable_column_names,
+ "columns": datasource.column_names,
+ "ordering_cols": order_by_choices
}
form_data = dict(
column_opts.items() + datasource.time_column_grains.items()