diff --git a/caravel/assets/javascripts/explorev2/actions/exploreActions.js b/caravel/assets/javascripts/explorev2/actions/exploreActions.js
index 6b4bad7d3e13b..d836dd864bb44 100644
--- a/caravel/assets/javascripts/explorev2/actions/exploreActions.js
+++ b/caravel/assets/javascripts/explorev2/actions/exploreActions.js
@@ -17,7 +17,7 @@ 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_TYPE = 'SET_DATASOURCE_TYPE';
-export const SET_FORM_DATA = 'SET_FORM_DATA';
+export const SET_FIELD_VALUE = 'SET_FIELD_VALUE';
export function setTimeColumnOpts(timeColumnOpts) {
return { type: SET_TIME_COLUMN_OPTS, timeColumnOpts };
@@ -47,19 +47,10 @@ export function setFilterColumnOpts(filterColumnOpts) {
return { type: SET_FILTER_COLUMN_OPTS, filterColumnOpts };
}
-export function resetFormData() {
- // Clear all form data when switching datasource
- return { type: RESET_FORM_DATA };
-}
-
export function clearAllOpts() {
return { type: CLEAR_ALL_OPTS };
}
-export function setDatasourceType(datasourceType) {
- return { type: SET_DATASOURCE_TYPE, datasourceType };
-}
-
export function setFormOpts(datasourceId, datasourceType) {
return function (dispatch) {
const timeColumnOpts = [];
@@ -114,15 +105,6 @@ export function setFormOpts(datasourceId, datasourceType) {
}
};
}
-
-export function setDatasource(datasourceId) {
- return { type: SET_DATASOURCE, datasourceId };
-}
-
-export function toggleSearchBox(searchBox) {
- return { type: TOGGLE_SEARCHBOX, searchBox };
-}
-
export function addFilter(filter) {
return { type: ADD_FILTER, filter };
}
@@ -143,6 +125,6 @@ export function changeFilterValue(filter, value) {
return { type: CHANGE_FILTER_VALUE, filter, value };
}
-export function setFormData(key, value) {
- return { type: SET_FORM_DATA, key, value };
+export function setFieldValue(key, value) {
+ return { type: SET_FIELD_VALUE, key, value };
}
diff --git a/caravel/assets/javascripts/explorev2/components/ChartContainer.jsx b/caravel/assets/javascripts/explorev2/components/ChartContainer.jsx
index 887738d2b803a..287836bffd0a8 100644
--- a/caravel/assets/javascripts/explorev2/components/ChartContainer.jsx
+++ b/caravel/assets/javascripts/explorev2/components/ChartContainer.jsx
@@ -6,12 +6,12 @@ import visMap from '../../../visualizations/main';
import { d3format } from '../../modules/utils';
const propTypes = {
- sliceName: PropTypes.string.isRequired,
- vizType: PropTypes.string.isRequired,
+ slice_name: PropTypes.string.isRequired,
+ viz_type: PropTypes.string.isRequired,
height: PropTypes.string.isRequired,
containerId: PropTypes.string.isRequired,
- jsonEndpoint: PropTypes.string.isRequired,
- columnFormats: PropTypes.object,
+ json_endpoint: PropTypes.string.isRequired,
+ column_formats: PropTypes.object,
};
class ChartContainer extends React.Component {
@@ -33,8 +33,7 @@ class ChartContainer extends React.Component {
getMockedSliceObject() {
return {
containerId: this.props.containerId,
-
- jsonEndpoint: () => this.props.jsonEndpoint,
+ jsonEndpoint: () => this.props.json_endpoint,
container: {
html: (data) => {
@@ -104,7 +103,7 @@ class ChartContainer extends React.Component {
d3format: (col, number) => {
// mock d3format function in Slice object in caravel.js
- const format = this.props.columnFormats[col];
+ const format = this.props.column_formats[col];
return d3format(format, number);
},
};
@@ -112,7 +111,7 @@ class ChartContainer extends React.Component {
renderVis() {
const slice = this.getMockedSliceObject();
- visMap[this.props.vizType](slice).render();
+ visMap[this.props.viz_type](slice).render();
}
render() {
@@ -125,14 +124,14 @@ class ChartContainer extends React.Component {
id="slice-header"
className="panel-title"
>
- {this.props.sliceName}
+ {this.props.slice_name}
}
>
{ this.chartContainerRef = ref; }}
- className={this.props.vizType}
+ className={this.props.viz_type}
/>
@@ -144,11 +143,11 @@ ChartContainer.propTypes = propTypes;
function mapStateToProps(state) {
return {
- sliceName: state.sliceName,
- vizType: state.viz.formData.vizType,
- containerId: `slice-container-${state.viz.formData.sliceId}`,
- jsonEndpoint: state.viz.jsonEndPoint,
- columnFormats: state.viz.columnFormats,
+ containerId: `slice-container-${state.viz.form_data.slice_id}`,
+ slice_name: state.viz.form_data.slice_name,
+ viz_type: state.viz.form_data.viz_type,
+ json_endpoint: state.viz.json_endpoint,
+ column_formats: state.viz.column_formats,
};
}
diff --git a/caravel/assets/javascripts/explorev2/components/CheckboxField.jsx b/caravel/assets/javascripts/explorev2/components/CheckboxField.jsx
index 6398b6443b276..0996b90396c5e 100644
--- a/caravel/assets/javascripts/explorev2/components/CheckboxField.jsx
+++ b/caravel/assets/javascripts/explorev2/components/CheckboxField.jsx
@@ -3,21 +3,29 @@ import { Checkbox } from 'react-bootstrap';
import ControlLabelWithTooltip from './ControlLabelWithTooltip';
const propTypes = {
+ name: PropTypes.string.isRequired,
label: PropTypes.string,
description: PropTypes.string,
+ onChange: PropTypes.func,
};
const defaultProps = {
label: null,
description: null,
+ onChange: () => {},
};
-export default function CheckboxField({ label, description }) {
- return (
-
-
-
- );
+export default class CheckboxField extends React.Component {
+ onToggle() {
+ this.props.onChange(this.props.name);
+ }
+ render() {
+ return (
+
+
+
+ );
+ }
}
CheckboxField.propTypes = propTypes;
diff --git a/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx b/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
index 04f25f9b2ea0e..7b2a8de9dc5a4 100644
--- a/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
+++ b/caravel/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx
@@ -1,3 +1,4 @@
+/* eslint camelcase: 0 */
import React, { PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import * as actions from '../actions/exploreActions';
@@ -8,26 +9,30 @@ import ControlPanelSection from './ControlPanelSection';
import FieldSetRow from './FieldSetRow';
const propTypes = {
- vizType: PropTypes.string,
- datasourceId: PropTypes.number.isRequired,
- datasourceType: PropTypes.string.isRequired,
+ viz_type: PropTypes.string,
+ datasource_id: PropTypes.number.isRequired,
+ datasource_type: PropTypes.string.isRequired,
actions: PropTypes.object.isRequired,
};
const defaultProps = {
- vizType: null,
+ viz_type: null,
};
class ControlPanelsContainer extends React.Component {
componentWillMount() {
- const { datasourceId, datasourceType } = this.props;
- if (datasourceId) {
- this.props.actions.setFormOpts(datasourceId, datasourceType);
+ const { datasource_id, datasource_type } = this.props;
+ if (datasource_id) {
+ this.props.actions.setFormOpts(datasource_id, datasource_type);
}
}
+ onChange(name, value) {
+ this.props.actions.setFieldValue(name, value);
+ }
+
sectionsToRender() {
- const viz = visTypes[this.props.vizType];
+ const viz = visTypes[this.props.viz_type];
const { datasourceAndVizType, sqlClause } = commonControlPanelSections;
const sectionsToRender = [datasourceAndVizType].concat(viz.controlPanelSections, sqlClause);
@@ -35,7 +40,7 @@ class ControlPanelsContainer extends React.Component {
}
fieldOverrides() {
- const viz = visTypes[this.props.vizType];
+ const viz = visTypes[this.props.viz_type];
return viz.fieldOverrides;
}
@@ -55,6 +60,7 @@ class ControlPanelsContainer extends React.Component {
key={`${section.label}-fieldSetRow-${i}`}
fieldSets={fieldSets}
fieldOverrides={this.fieldOverrides()}
+ onChange={this.onChange.bind(this)}
/>
))}
@@ -72,9 +78,9 @@ ControlPanelsContainer.defaultProps = defaultProps;
function mapStateToProps(state) {
return {
- datasourceId: state.datasourceId,
- datasourceType: state.datasourceType,
- vizType: state.viz.formData.vizType,
+ datasource_id: state.datasource_id,
+ datasource_type: state.datasource_type,
+ viz_type: state.viz.form_data.viz_type,
};
}
diff --git a/caravel/assets/javascripts/explorev2/components/FieldSet.jsx b/caravel/assets/javascripts/explorev2/components/FieldSet.jsx
index ef6f5659b32cd..0fbfdbfdc0795 100644
--- a/caravel/assets/javascripts/explorev2/components/FieldSet.jsx
+++ b/caravel/assets/javascripts/explorev2/components/FieldSet.jsx
@@ -6,12 +6,14 @@ import SelectField from './SelectField';
import { fieldTypes } from '../stores/store';
const propTypes = {
+ name: PropTypes.string.isRequired,
type: PropTypes.oneOf(fieldTypes).isRequired,
label: PropTypes.string.isRequired,
choices: PropTypes.arrayOf(PropTypes.array),
description: PropTypes.string,
places: PropTypes.number,
validators: PropTypes.any,
+ onChange: React.PropTypes.func,
};
const defaultProps = {
@@ -19,23 +21,36 @@ const defaultProps = {
description: null,
places: null,
validators: null,
+ onChange: () => {},
};
export default class FieldSet extends React.Component {
renderCheckBoxField() {
- return ;
+ return (
+ );
}
renderTextAreaField() {
- return ;
+ return (
+ );
}
renderSelectField() {
- return ;
+ return (
+ );
}
renderTextField() {
- return ;
+ return (
+ );
}
render() {
diff --git a/caravel/assets/javascripts/explorev2/components/FieldSetRow.jsx b/caravel/assets/javascripts/explorev2/components/FieldSetRow.jsx
index b699b0301b50e..8ab8b877db445 100644
--- a/caravel/assets/javascripts/explorev2/components/FieldSetRow.jsx
+++ b/caravel/assets/javascripts/explorev2/components/FieldSetRow.jsx
@@ -5,10 +5,12 @@ import { fields } from '../stores/store';
const propTypes = {
fieldSets: PropTypes.array.isRequired,
fieldOverrides: PropTypes.object,
+ onChange: PropTypes.func,
};
const defaultProps = {
fieldOverrides: {},
+ onChange: () => {},
};
function getFieldData(fs, fieldOverrides) {
@@ -20,12 +22,15 @@ function getFieldData(fs, fieldOverrides) {
return fieldData;
}
-export default function FieldSetRow({ fieldSets, fieldOverrides }) {
+export default function FieldSetRow({ fieldSets, fieldOverrides, onChange }) {
return (
{fieldSets.map((fs) => {
const fieldData = getFieldData(fs, fieldOverrides);
- return ;
+ return (
+ -
+
+
);
})}
);
diff --git a/caravel/assets/javascripts/explorev2/components/SelectField.jsx b/caravel/assets/javascripts/explorev2/components/SelectField.jsx
index 6cbd09ac7792d..c50e0cdf59fad 100644
--- a/caravel/assets/javascripts/explorev2/components/SelectField.jsx
+++ b/caravel/assets/javascripts/explorev2/components/SelectField.jsx
@@ -4,25 +4,40 @@ import ControlLabelWithTooltip from './ControlLabelWithTooltip';
import { slugify } from '../../modules/utils';
const propTypes = {
+ name: PropTypes.string.isRequired,
label: PropTypes.string,
description: PropTypes.string,
+ onChange: PropTypes.func,
};
const defaultProps = {
label: null,
description: null,
+ onChange: () => {},
};
-export default function SelectField({ label, description }) {
- return (
-
-
-
-
-
-
-
- );
+export default class SelectField extends React.Component {
+ onChange(opt) {
+ this.props.onChange(this.props.name, opt.target.value);
+ }
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
}
SelectField.propTypes = propTypes;
diff --git a/caravel/assets/javascripts/explorev2/components/TextAreaField.jsx b/caravel/assets/javascripts/explorev2/components/TextAreaField.jsx
index 42c8a0089cc35..761ab70f47071 100644
--- a/caravel/assets/javascripts/explorev2/components/TextAreaField.jsx
+++ b/caravel/assets/javascripts/explorev2/components/TextAreaField.jsx
@@ -3,22 +3,34 @@ import { FormGroup, FormControl } from 'react-bootstrap';
import ControlLabelWithTooltip from './ControlLabelWithTooltip';
const propTypes = {
+ name: PropTypes.string.isRequired,
label: PropTypes.string,
description: PropTypes.string,
+ onChange: PropTypes.func,
};
const defaultProps = {
label: null,
description: null,
+ onChange: () => {},
};
-export default function TextAreaField({ label, description }) {
- return (
-
-
-
-
- );
+export default class TextAreaField extends React.Component {
+ onChange(event) {
+ this.props.onChange(this.props.name, event.target.value);
+ }
+ render() {
+ return (
+
+
+
+
+ );
+ }
}
TextAreaField.propTypes = propTypes;
diff --git a/caravel/assets/javascripts/explorev2/components/TextField.jsx b/caravel/assets/javascripts/explorev2/components/TextField.jsx
index b562f622f8117..65f44f4c67e62 100644
--- a/caravel/assets/javascripts/explorev2/components/TextField.jsx
+++ b/caravel/assets/javascripts/explorev2/components/TextField.jsx
@@ -3,22 +3,33 @@ import { FormGroup, FormControl } from 'react-bootstrap';
import ControlLabelWithTooltip from './ControlLabelWithTooltip';
const propTypes = {
+ name: PropTypes.string.isRequired,
label: PropTypes.string,
description: PropTypes.string,
+ onChange: PropTypes.func,
};
const defaultProps = {
label: null,
description: null,
+ onChange: () => {},
};
-export default function TextField({ label, description }) {
- return (
-
-
-
-
- );
+export default class TextField extends React.Component {
+ onChange(event) {
+ this.props.onChange(this.props.name, event.target.value);
+ }
+ render() {
+ return (
+
+
+
+
+ );
+ }
}
TextField.propTypes = propTypes;
diff --git a/caravel/assets/javascripts/explorev2/index.jsx b/caravel/assets/javascripts/explorev2/index.jsx
index b26857bb22fcf..73fef9878f541 100644
--- a/caravel/assets/javascripts/explorev2/index.jsx
+++ b/caravel/assets/javascripts/explorev2/index.jsx
@@ -14,27 +14,9 @@ import { exploreReducer } from './reducers/exploreReducer';
const bootstrappedState = Object.assign(initialState, {
datasources: bootstrapData.datasources,
- datasourceId: parseInt(bootstrapData.datasource_id, 10),
- datasourceType: bootstrapData.datasource_type,
- sliceName: bootstrapData.viz.form_data.slice_name,
- viz: {
- jsonEndPoint: bootstrapData.viz.json_endpoint,
- data: bootstrapData.viz.data,
- columnFormats: bootstrapData.viz.column_formats,
- formData: {
- 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.metrics].map((m) => ({ value: m, label: m })),
- since: bootstrapData.viz.form_data.since,
- until: bootstrapData.viz.form_data.until,
- having: bootstrapData.viz.form_data.having,
- where: bootstrapData.viz.form_data.where,
- rowLimit: bootstrapData.viz.form_data.row_limit,
- timeStampFormat: bootstrapData.viz.form_data.table_timestamp_format,
- },
- },
+ datasource_id: parseInt(bootstrapData.datasource_id, 10),
+ datasource_type: bootstrapData.datasource_type,
+ viz: bootstrapData.viz,
});
const store = createStore(exploreReducer, bootstrappedState,
compose(applyMiddleware(thunk))
diff --git a/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js b/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
index 8ff9b361cb681..93d7fe5f09bb6 100644
--- a/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
+++ b/caravel/assets/javascripts/explorev2/reducers/exploreReducer.js
@@ -1,31 +1,9 @@
-import { defaultFormData, defaultOpts } from '../stores/store';
+import { defaultOpts } from '../stores/store';
import * as actions from '../actions/exploreActions';
import { addToArr, removeFromArr, alterInArr } from '../../../utils/reducerUtils';
-const setFormInViz = function (state, action) {
- const newFormData = Object.assign({}, state);
- newFormData[action.key] = action.value;
- return newFormData;
-};
-
-const setVizInState = function (state, action) {
- switch (action.type) {
- case actions.SET_FORM_DATA:
- return Object.assign(
- {},
- state,
- { formData: setFormInViz(state.formData, action) }
- );
- default:
- return state;
- }
-};
-
export const exploreReducer = function (state, action) {
const actionHandlers = {
- [actions.SET_DATASOURCE]() {
- return Object.assign({}, state, { datasourceId: action.datasourceId });
- },
[actions.SET_TIME_COLUMN_OPTS]() {
return Object.assign({}, state, { timeColumnOpts: action.timeColumnOpts });
},
@@ -44,9 +22,6 @@ export const exploreReducer = function (state, action) {
[actions.SET_ORDERING_OPTS]() {
return Object.assign({}, state, { orderingOpts: action.orderingOpts });
},
- [actions.TOGGLE_SEARCHBOX]() {
- return Object.assign({}, state, { searchBox: action.searchBox });
- },
[actions.SET_FILTER_COLUMN_OPTS]() {
return Object.assign({}, state, { filterColumnOpts: action.filterColumnOpts });
},
@@ -65,21 +40,14 @@ export const exploreReducer = function (state, action) {
[actions.CHANGE_FILTER_VALUE]() {
return alterInArr(state, 'filters', action.filter, { value: action.value });
},
- [actions.RESET_FORM_DATA]() {
- return Object.assign({}, state, defaultFormData);
- },
[actions.CLEAR_ALL_OPTS]() {
return Object.assign({}, state, defaultOpts);
},
- [actions.SET_DATASOURCE_TYPE]() {
- return Object.assign({}, state, { datasourceType: action.datasourceType });
- },
- [actions.SET_FORM_DATA]() {
- return Object.assign(
- {},
- state,
- { viz: setVizInState(state.viz, action) }
- );
+ [actions.SET_FIELD_VALUE]() {
+ const newState = Object.assign({}, state);
+ newState.viz.form_data[action.key] =
+ action.value ? action.value : (!state.viz.form_data[action.key]);
+ return newState;
},
};
if (action.type in actionHandlers) {
diff --git a/caravel/assets/javascripts/explorev2/stores/store.js b/caravel/assets/javascripts/explorev2/stores/store.js
index 14b6fbbbe4cfb..d5db2f9c17fe9 100644
--- a/caravel/assets/javascripts/explorev2/stores/store.js
+++ b/caravel/assets/javascripts/explorev2/stores/store.js
@@ -11,60 +11,6 @@ export const fieldTypes = [
'TextField',
];
-// TODO: add datasource_type here after druid support is added
-export const defaultFormData = {
- sliceId: null,
- vizType: null,
- timeColumn: null,
- timeGrain: null,
- groupByColumns: [],
- metrics: [],
- since: null,
- until: null,
- having: null,
- where: null,
- columns: [],
- orderings: [],
- timeStampFormat: 'smart_date',
- rowLimit: 50000,
- searchBox: false,
- whereClause: '',
- havingClause: '',
- filters: [],
-};
-
-export const initialState = {
- datasources: null,
- datasourceId: null,
- datasourceType: null,
- timeColumnOpts: [],
- timeGrainOpts: [],
- timeGrain: null,
- groupByColumnOpts: [],
- metricsOpts: [],
- columnOpts: [],
- orderingOpts: [],
- searchBox: false,
- whereClause: '',
- havingClause: '',
- filters: [],
- filterColumnOpts: [],
- viz: {
- columnFormats: {},
- formData: defaultFormData,
- },
-};
-
-export const defaultOpts = {
- timeColumnOpts: [],
- timeGrainOpts: [],
- groupByColumnOpts: [],
- metricsOpts: [],
- filterColumnOpts: [],
- columnOpts: [],
- orderingOpts: [],
-};
-
const D3_FORMAT_DOCS = 'D3 format syntax: https://github.com/d3/d3-format';
// input choices & options
@@ -1082,7 +1028,7 @@ export const fields = {
choices: [['granularity_sqla', 'granularity_sqla']],
description: 'The time column for the visualization. Note that you ' +
'can define arbitrary expression that return a DATETIME ' +
- 'column in the table editor. Also note that the ' +
+ 'column in the table or. Also note that the ' +
'filter below is applied against this column or ' +
'expression',
},
@@ -1679,3 +1625,46 @@ export const fields = {
description: 'The color for points and clusters in RGB',
},
};
+
+const defaultFormData = {};
+defaultFormData.slice_name = null;
+defaultFormData.slice_id = null;
+Object.keys(fields).forEach((k) => { defaultFormData[k] = fields[k].default; });
+
+export const defaultViz = {
+ cached_key: null,
+ cached_timeout: null,
+ cached_dttm: null,
+ column_formats: null,
+ csv_endpoint: null,
+ is_cached: false,
+ data: [],
+ form_data: defaultFormData,
+ json_endpoint: null,
+ query: null,
+ standalone_endpoint: null,
+};
+
+export const initialState = {
+ datasources: null,
+ datasource_id: null,
+ datasource_type: null,
+ timeColumnOpts: [],
+ timeGrainOpts: [],
+ groupByColumnOpts: [],
+ metricsOpts: [],
+ columnOpts: [],
+ orderingOpts: [],
+ filterColumnOpts: [],
+ viz: defaultViz,
+};
+
+export const defaultOpts = {
+ timeColumnOpts: [],
+ timeGrainOpts: [],
+ 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
deleted file mode 100644
index 808822c3b8bf3..0000000000000
--- a/caravel/assets/spec/javascripts/explore/components/actions_spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { it, describe } from 'mocha';
-import { expect } from 'chai';
-import shortid from 'shortid';
-import * as actions from '../../../../javascripts/explorev2/actions/exploreActions';
-import { initialState } from '../../../../javascripts/explorev2/stores/store';
-import { exploreReducer } from '../../../../javascripts/explorev2/reducers/exploreReducer';
-
-describe('reducers', () => {
- it('should return new state with datasource id', () => {
- const newState = exploreReducer(initialState, actions.setDatasource(1));
- expect(newState.datasourceId).to.equal(1);
- });
-
- it('should return new state with search box toggled', () => {
- const newState = exploreReducer(initialState, actions.toggleSearchBox(true));
- expect(newState.searchBox).to.equal(true);
- });
-
- it('should return new state with added filter', () => {
- const newFilter = {
- id: shortid.generate(),
- eq: 'value',
- op: 'in',
- col: 'vals',
- };
- const newState = exploreReducer(initialState, actions.addFilter(newFilter));
- expect(newState.filters).to.deep.equal([newFilter]);
- });
-
- it('should return new state with removed filter', () => {
- const filter1 = {
- id: shortid.generate(),
- eq: 'value',
- op: 'in',
- col: 'vals1',
- };
- const filter2 = {
- id: shortid.generate(),
- eq: 'value',
- op: 'not in',
- col: 'vals2',
- };
- const testState = {
- initialState,
- filters: [filter1, filter2],
- };
- const newState = exploreReducer(testState, actions.removeFilter(filter1));
- expect(newState.filters).to.deep.equal([filter2]);
- });
-});
diff --git a/caravel/assets/spec/javascripts/explorev2/actions_spec.js b/caravel/assets/spec/javascripts/explorev2/actions_spec.js
new file mode 100644
index 0000000000000..c674fdf519948
--- /dev/null
+++ b/caravel/assets/spec/javascripts/explorev2/actions_spec.js
@@ -0,0 +1,16 @@
+import { it, describe } from 'mocha';
+import { expect } from 'chai';
+import * as actions from '../../../javascripts/explorev2/actions/exploreActions';
+import { initialState } from '../../../javascripts/explorev2/stores/store';
+import { exploreReducer } from '../../../javascripts/explorev2/reducers/exploreReducer';
+
+describe('reducers', () => {
+ it('sets correct field value given a key and value', () => {
+ const newState = exploreReducer(initialState, actions.setFieldValue('x_axis_label', 'x'));
+ expect(newState.viz.form_data.x_axis_label).to.equal('x');
+ });
+ it('toggles a boolean field value given only a key', () => {
+ const newState = exploreReducer(initialState, actions.setFieldValue('show_legend'));
+ expect(newState.viz.form_data.show_legend).to.equal(false);
+ });
+});
diff --git a/caravel/assets/spec/javascripts/explorev2/components/CheckboxField_spec.js b/caravel/assets/spec/javascripts/explorev2/components/CheckboxField_spec.js
new file mode 100644
index 0000000000000..18a2ff9159a94
--- /dev/null
+++ b/caravel/assets/spec/javascripts/explorev2/components/CheckboxField_spec.js
@@ -0,0 +1,31 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import { Checkbox } from 'react-bootstrap';
+import sinon from 'sinon';
+import { expect } from 'chai';
+import { describe, it, beforeEach } from 'mocha';
+import { shallow } from 'enzyme';
+import CheckboxField from '../../../../javascripts/explorev2/components/CheckboxField';
+
+const defaultProps = {
+ name: 'show_legend',
+ onChange: sinon.spy(),
+};
+
+describe('CheckboxField', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+
+ it('renders a Checkbox', () => {
+ expect(wrapper.find(Checkbox)).to.have.lengthOf(1);
+ });
+
+ it('calls onChange when toggled', () => {
+ const checkbox = wrapper.find(Checkbox);
+ checkbox.simulate('change', { value: true });
+ expect(defaultProps.onChange.calledWith('show_legend')).to.be.true;
+ });
+});
diff --git a/caravel/assets/spec/javascripts/explorev2/components/ControlPanelsContainer_spec.js b/caravel/assets/spec/javascripts/explorev2/components/ControlPanelsContainer_spec.js
index 74eb50de34a01..924fb42b468b8 100644
--- a/caravel/assets/spec/javascripts/explorev2/components/ControlPanelsContainer_spec.js
+++ b/caravel/assets/spec/javascripts/explorev2/components/ControlPanelsContainer_spec.js
@@ -9,9 +9,9 @@ import {
} from '../../../../javascripts/explorev2/components/ControlPanelsContainer';
const defaultProps = {
- vizType: 'dist_bar',
- datasourceId: 1,
- datasourceType: 'type',
+ viz_type: 'dist_bar',
+ datasource_id: 1,
+ datasource_type: 'type',
actions: {
setFormOpts: () => {
// noop
diff --git a/caravel/assets/spec/javascripts/explorev2/components/SelectField_spec.js b/caravel/assets/spec/javascripts/explorev2/components/SelectField_spec.js
new file mode 100644
index 0000000000000..7b22cf010f72b
--- /dev/null
+++ b/caravel/assets/spec/javascripts/explorev2/components/SelectField_spec.js
@@ -0,0 +1,32 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import { FormControl } from 'react-bootstrap';
+import sinon from 'sinon';
+import { expect } from 'chai';
+import { describe, it, beforeEach } from 'mocha';
+import { shallow } from 'enzyme';
+import SelectField from '../../../../javascripts/explorev2/components/SelectField';
+
+const defaultProps = {
+ name: 'row_limit',
+ label: 'Row Limit',
+ onChange: sinon.spy(),
+};
+
+describe('SelectField', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+
+ it('renders a FormControl', () => {
+ expect(wrapper.find(FormControl)).to.have.lengthOf(1);
+ });
+
+ it('calls onChange when toggled', () => {
+ const select = wrapper.find(FormControl);
+ select.simulate('change', { target: { value: 50 } });
+ expect(defaultProps.onChange.calledWith('row_limit', 50)).to.be.true;
+ });
+});
diff --git a/caravel/assets/spec/javascripts/explorev2/components/TextArea_spec.js b/caravel/assets/spec/javascripts/explorev2/components/TextArea_spec.js
new file mode 100644
index 0000000000000..eb337ddd5ddc7
--- /dev/null
+++ b/caravel/assets/spec/javascripts/explorev2/components/TextArea_spec.js
@@ -0,0 +1,32 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import { FormControl } from 'react-bootstrap';
+import sinon from 'sinon';
+import { expect } from 'chai';
+import { describe, it, beforeEach } from 'mocha';
+import { shallow } from 'enzyme';
+import TextAreaField from '../../../../javascripts/explorev2/components/TextAreaField';
+
+const defaultProps = {
+ name: 'x_axis_label',
+ label: 'X Axis Label',
+ onChange: sinon.spy(),
+};
+
+describe('SelectField', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+
+ it('renders a FormControl', () => {
+ expect(wrapper.find(FormControl)).to.have.lengthOf(1);
+ });
+
+ it('calls onChange when toggled', () => {
+ const select = wrapper.find(FormControl);
+ select.simulate('change', { target: { value: 'x' } });
+ expect(defaultProps.onChange.calledWith('x_axis_label', 'x')).to.be.true;
+ });
+});