You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by GitBox <gi...@apache.org> on 2018/07/23 20:08:02 UTC

[GitHub] mistercrunch closed pull request #5276: Move controls to top level folder

mistercrunch closed pull request #5276: Move controls to top level folder
URL: https://github.com/apache/incubator-superset/pull/5276
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/superset/assets/spec/javascripts/explore/AdhocFilter_spec.js b/superset/assets/spec/javascripts/explore/AdhocFilter_spec.js
index 36d3bdd095..44d6c13dff 100644
--- a/superset/assets/spec/javascripts/explore/AdhocFilter_spec.js
+++ b/superset/assets/spec/javascripts/explore/AdhocFilter_spec.js
@@ -1,7 +1,7 @@
 import { expect } from 'chai';
 import { describe, it } from 'mocha';
 
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../src/explore/AdhocFilter';
+import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../src/controls/AdhocFilter';
 
 describe('AdhocFilter', () => {
   it('sets filterOptionName in constructor', () => {
diff --git a/superset/assets/spec/javascripts/explore/AdhocMetric_spec.js b/superset/assets/spec/javascripts/explore/AdhocMetric_spec.js
index 432be7620a..890d1b31a5 100644
--- a/superset/assets/spec/javascripts/explore/AdhocMetric_spec.js
+++ b/superset/assets/spec/javascripts/explore/AdhocMetric_spec.js
@@ -1,8 +1,8 @@
 import { expect } from 'chai';
 import { describe, it } from 'mocha';
 
-import AdhocMetric, { EXPRESSION_TYPES } from '../../../src/explore/AdhocMetric';
-import { AGGREGATES } from '../../../src/explore/constants';
+import AdhocMetric, { EXPRESSION_TYPES } from '../../../src/controls/AdhocMetric';
+import { AGGREGATES } from '../../../src/controls/constants';
 
 const valueColumn = { type: 'DOUBLE', column_name: 'value' };
 
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx
deleted file mode 100644
index 2123ed7c2e..0000000000
--- a/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx
+++ /dev/null
@@ -1,137 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it } from 'mocha';
-import { shallow } from 'enzyme';
-
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/explore/AdhocFilter';
-import AdhocFilterControl from '../../../../src/explore/components/controls/AdhocFilterControl';
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import { AGGREGATES, OPERATORS } from '../../../../src/explore/constants';
-import OnPasteSelect from '../../../../src/components/OnPasteSelect';
-
-const simpleAdhocFilter = new AdhocFilter({
-  expressionType: EXPRESSION_TYPES.SIMPLE,
-  subject: 'value',
-  operator: '>',
-  comparator: '10',
-  clause: CLAUSES.WHERE,
-});
-
-const sumValueAdhocMetric = new AdhocMetric({
-  expressionType: EXPRESSION_TYPES.SIMPLE,
-  column: { type: 'VARCHAR(255)', column_name: 'source' },
-  aggregate: AGGREGATES.SUM,
-});
-
-const savedMetric = { metric_name: 'sum__value', expression: 'SUM(value)' };
-
-const columns = [
-  { type: 'VARCHAR(255)', column_name: 'source' },
-  { type: 'VARCHAR(255)', column_name: 'target' },
-  { type: 'DOUBLE', column_name: 'value' },
-];
-
-const formData = {
-  metric: undefined,
-  metrics: [sumValueAdhocMetric, savedMetric.saved_metric_name],
-};
-
-function setup(overrides) {
-  const onChange = sinon.spy();
-  const props = {
-    onChange,
-    value: [simpleAdhocFilter],
-    datasource: { type: 'table' },
-    columns,
-    savedMetrics: [savedMetric],
-    formData,
-    ...overrides,
-  };
-  const wrapper = shallow(<AdhocFilterControl {...props} />);
-  return { wrapper, onChange };
-}
-
-describe('AdhocFilterControl', () => {
-  it('renders an onPasteSelect', () => {
-    const { wrapper } = setup();
-    expect(wrapper.find(OnPasteSelect)).to.have.lengthOf(1);
-  });
-
-  it('handles saved metrics being selected to filter on', () => {
-    const { wrapper, onChange } = setup({ value: [] });
-    const select = wrapper.find(OnPasteSelect);
-    select.simulate('change', [{ saved_metric_name: 'sum__value' }]);
-
-    const adhocFilter = onChange.lastCall.args[0][0];
-    expect(adhocFilter instanceof AdhocFilter).to.be.true;
-    expect(adhocFilter.equals((
-      new AdhocFilter({
-        expressionType: EXPRESSION_TYPES.SQL,
-        subject: savedMetric.expression,
-        operator: OPERATORS['>'],
-        comparator: 0,
-        clause: CLAUSES.HAVING,
-      })
-    ))).to.be.true;
-  });
-
-  it('handles adhoc metrics being selected to filter on', () => {
-    const { wrapper, onChange } = setup({ value: [] });
-    const select = wrapper.find(OnPasteSelect);
-    select.simulate('change', [sumValueAdhocMetric]);
-
-    const adhocFilter = onChange.lastCall.args[0][0];
-    expect(adhocFilter instanceof AdhocFilter).to.be.true;
-    expect(adhocFilter.equals((
-      new AdhocFilter({
-        expressionType: EXPRESSION_TYPES.SQL,
-        subject: sumValueAdhocMetric.label,
-        operator: OPERATORS['>'],
-        comparator: 0,
-        clause: CLAUSES.HAVING,
-      })
-    ))).to.be.true;
-  });
-
-  it('handles columns being selected to filter on', () => {
-    const { wrapper, onChange } = setup({ value: [] });
-    const select = wrapper.find(OnPasteSelect);
-    select.simulate('change', [columns[0]]);
-
-    const adhocFilter = onChange.lastCall.args[0][0];
-    expect(adhocFilter instanceof AdhocFilter).to.be.true;
-    expect(adhocFilter.equals((
-      new AdhocFilter({
-        expressionType: EXPRESSION_TYPES.SIMPLE,
-        subject: columns[0].column_name,
-        operator: OPERATORS['=='],
-        comparator: '',
-        clause: CLAUSES.WHERE,
-      })
-    ))).to.be.true;
-  });
-
-  it('persists existing filters even when new filters are added', () => {
-    const { wrapper, onChange } = setup();
-    const select = wrapper.find(OnPasteSelect);
-    select.simulate('change', [simpleAdhocFilter, columns[0]]);
-
-    const existingAdhocFilter = onChange.lastCall.args[0][0];
-    expect(existingAdhocFilter instanceof AdhocFilter).to.be.true;
-    expect(existingAdhocFilter.equals(simpleAdhocFilter)).to.be.true;
-
-    const newAdhocFilter = onChange.lastCall.args[0][1];
-    expect(newAdhocFilter instanceof AdhocFilter).to.be.true;
-    expect(newAdhocFilter.equals((
-      new AdhocFilter({
-        expressionType: EXPRESSION_TYPES.SIMPLE,
-        subject: columns[0].column_name,
-        operator: OPERATORS['=='],
-        comparator: '',
-        clause: CLAUSES.WHERE,
-      })
-    ))).to.be.true;
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx
index 2014bbc7c9..8dad939329 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSimpleTabContent_spec.jsx
@@ -6,10 +6,10 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { FormGroup } from 'react-bootstrap';
 
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/explore/AdhocFilter';
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import AdhocFilterEditPopoverSimpleTabContent from '../../../../src/explore/components/AdhocFilterEditPopoverSimpleTabContent';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/controls/AdhocFilter';
+import AdhocMetric from '../../../../src/controls/AdhocMetric';
+import AdhocFilterEditPopoverSimpleTabContent from '../../../../src/controls/controls/AdhocFilterEditPopoverSimpleTabContent';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const simpleAdhocFilter = new AdhocFilter({
   expressionType: EXPRESSION_TYPES.SIMPLE,
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSqlTabContent_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSqlTabContent_spec.jsx
index a1cdb23247..9134644ef4 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSqlTabContent_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopoverSqlTabContent_spec.jsx
@@ -6,8 +6,8 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { FormGroup } from 'react-bootstrap';
 
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/explore/AdhocFilter';
-import AdhocFilterEditPopoverSqlTabContent from '../../../../src/explore/components/AdhocFilterEditPopoverSqlTabContent';
+import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/controls/AdhocFilter';
+import AdhocFilterEditPopoverSqlTabContent from '../../../../src/controls/controls/AdhocFilterEditPopoverSqlTabContent';
 
 const sqlAdhocFilter = new AdhocFilter({
   expressionType: EXPRESSION_TYPES.SQL,
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
index 3b062ed272..9ec06a2d71 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
@@ -6,12 +6,12 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
 
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/explore/AdhocFilter';
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import AdhocFilterEditPopover from '../../../../src/explore/components/AdhocFilterEditPopover';
-import AdhocFilterEditPopoverSimpleTabContent from '../../../../src/explore/components/AdhocFilterEditPopoverSimpleTabContent';
-import AdhocFilterEditPopoverSqlTabContent from '../../../../src/explore/components/AdhocFilterEditPopoverSqlTabContent';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/controls/AdhocFilter';
+import AdhocMetric from '../../../../src/controls/AdhocMetric';
+import AdhocFilterEditPopover from '../../../../src/controls/controls/AdhocFilterEditPopover';
+import AdhocFilterEditPopoverSimpleTabContent from '../../../../src/controls/controls/AdhocFilterEditPopoverSimpleTabContent';
+import AdhocFilterEditPopoverSqlTabContent from '../../../../src/controls/controls/AdhocFilterEditPopoverSqlTabContent';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const simpleAdhocFilter = new AdhocFilter({
   expressionType: EXPRESSION_TYPES.SIMPLE,
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
index 673b854e5c..c56ccef30b 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
@@ -6,8 +6,8 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { Label, OverlayTrigger } from 'react-bootstrap';
 
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/explore/AdhocFilter';
-import AdhocFilterOption from '../../../../src/explore/components/AdhocFilterOption';
+import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../../../../src/controls/AdhocFilter';
+import AdhocFilterOption from '../../../../src/controls/controls/AdhocFilterOption';
 
 const simpleAdhocFilter = new AdhocFilter({
   expressionType: EXPRESSION_TYPES.SIMPLE,
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopoverTitle_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopoverTitle_spec.jsx
index 4acb24e279..6e81ba1218 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopoverTitle_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopoverTitle_spec.jsx
@@ -6,9 +6,9 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { OverlayTrigger } from 'react-bootstrap';
 
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import AdhocMetricEditPopoverTitle from '../../../../src/explore/components/AdhocMetricEditPopoverTitle';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetric from '../../../../src/controls/AdhocMetric';
+import AdhocMetricEditPopoverTitle from '../../../../src/controls/controls/AdhocMetricEditPopoverTitle';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const columns = [
   { type: 'VARCHAR(255)', column_name: 'source' },
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
index eebc703869..409e061463 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
@@ -6,9 +6,9 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { Button, FormGroup, Popover } from 'react-bootstrap';
 
-import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/explore/AdhocMetric';
-import AdhocMetricEditPopover from '../../../../src/explore/components/AdhocMetricEditPopover';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/controls/AdhocMetric';
+import AdhocMetricEditPopover from '../../../../src/controls/controls/AdhocMetricEditPopover';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const columns = [
   { type: 'VARCHAR(255)', column_name: 'source' },
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
index 4ed5d68d7d..28921fdb22 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
@@ -6,9 +6,9 @@ import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { Label, OverlayTrigger } from 'react-bootstrap';
 
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import AdhocMetricOption from '../../../../src/explore/components/AdhocMetricOption';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetric from '../../../../src/controls/AdhocMetric';
+import AdhocMetricOption from '../../../../src/controls/controls/AdhocMetricOption';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const columns = [
   { type: 'VARCHAR(255)', column_name: 'source' },
diff --git a/superset/assets/spec/javascripts/explore/components/AdhocMetricStaticOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocMetricStaticOption_spec.jsx
index 54ff78e66f..2a90438b1c 100644
--- a/superset/assets/spec/javascripts/explore/components/AdhocMetricStaticOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AdhocMetricStaticOption_spec.jsx
@@ -4,9 +4,9 @@ import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 
-import AdhocMetricStaticOption from '../../../../src/explore/components/AdhocMetricStaticOption';
-import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/explore/AdhocMetric';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetricStaticOption from '../../../../src/controls/AdhocMetricStaticOption';
+import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/controls/AdhocMetric';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const sumValueAdhocMetric = new AdhocMetric({
   expressionType: EXPRESSION_TYPES.SIMPLE,
diff --git a/superset/assets/spec/javascripts/explore/components/AggregateOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/AggregateOption_spec.jsx
index 233eb8d75f..5e3fb34bb4 100644
--- a/superset/assets/spec/javascripts/explore/components/AggregateOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/AggregateOption_spec.jsx
@@ -4,7 +4,7 @@ import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 
-import AggregateOption from '../../../../src/explore/components/AggregateOption';
+import AggregateOption from '../../../../src/controls/controls/AggregateOption';
 
 describe('AggregateOption', () => {
   it('renders the aggregate', () => {
diff --git a/superset/assets/spec/javascripts/explore/components/BoundsControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/BoundsControl_spec.jsx
deleted file mode 100644
index 522329a512..0000000000
--- a/superset/assets/spec/javascripts/explore/components/BoundsControl_spec.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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 { mount } from 'enzyme';
-
-import BoundsControl from '../../../../src/explore/components/controls/BoundsControl';
-
-const defaultProps = {
-  name: 'y_axis_bounds',
-  label: 'Bounds of the y axis',
-  onChange: sinon.spy(),
-};
-
-describe('BoundsControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = mount(<BoundsControl {...defaultProps} />);
-  });
-
-  it('renders two FormControls', () => {
-    expect(wrapper.find(FormControl)).to.have.lengthOf(2);
-  });
-
-  it('errors on non-numeric', () => {
-    wrapper.find(FormControl).first().simulate('change', { target: { value: 's' } });
-    expect(defaultProps.onChange.calledWith([null, null])).to.be.true;
-    expect(defaultProps.onChange.getCall(0).args[1][0]).to.contain('value should be numeric');
-  });
-  it('casts to numeric', () => {
-    wrapper.find(FormControl).first().simulate('change', { target: { value: '1' } });
-    wrapper.find(FormControl).last().simulate('change', { target: { value: '5' } });
-    expect(defaultProps.onChange.calledWith([1, 5])).to.be.true;
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/CheckboxControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/CheckboxControl_spec.jsx
deleted file mode 100644
index a3312450b0..0000000000
--- a/superset/assets/spec/javascripts/explore/components/CheckboxControl_spec.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-
-import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
-import ControlHeader from '../../../../src/explore/components/ControlHeader';
-import Checkbox from '../../../../src/components/Checkbox';
-
-const defaultProps = {
-  name: 'show_legend',
-  onChange: sinon.spy(),
-  value: false,
-  label: 'checkbox label',
-};
-
-describe('CheckboxControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<CheckboxControl {...defaultProps} />);
-  });
-
-  it('renders a Checkbox', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-
-    const headerWrapper = controlHeader.shallow();
-    expect(headerWrapper.find(Checkbox)).to.have.length(1);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx
deleted file mode 100644
index ec58638569..0000000000
--- a/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { OverlayTrigger } from 'react-bootstrap';
-import { SketchPicker } from 'react-color';
-
-import ColorPickerControl from
-  '../../../../src/explore/components/controls/ColorPickerControl';
-import ControlHeader from '../../../../src/explore/components/ControlHeader';
-
-const defaultProps = {
-  value: { },
-};
-
-describe('ColorPickerControl', () => {
-  let wrapper;
-  let inst;
-  beforeEach(() => {
-    wrapper = shallow(<ColorPickerControl {...defaultProps} />);
-    inst = wrapper.instance();
-  });
-
-  it('renders a OverlayTrigger', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-    expect(wrapper.find(OverlayTrigger)).to.have.length(1);
-  });
-
-  it('renders a OverlayTrigger', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-    expect(wrapper.find(OverlayTrigger)).to.have.length(1);
-  });
-
-  it('renders a Popover with a SketchPicker', () => {
-    const popOver = shallow(inst.renderPopover());
-    expect(popOver.find(SketchPicker)).to.have.lengthOf(1);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx
index a7d4d66ab6..dc6e668a80 100644
--- a/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx
@@ -6,7 +6,7 @@ import { mount } from 'enzyme';
 import { Creatable } from 'react-select';
 
 import ColorSchemeControl from
-  '../../../../src/explore/components/controls/ColorSchemeControl';
+  '../../../../src/controls/controls/ColorSchemeControl';
 import { ALL_COLOR_SCHEMES } from '../../../../src/modules/colors';
 
 const defaultProps = {
diff --git a/superset/assets/spec/javascripts/explore/components/ControlPanelSection_spec.jsx b/superset/assets/spec/javascripts/explore/components/ControlPanelSection_spec.jsx
deleted file mode 100644
index c63392e41e..0000000000
--- a/superset/assets/spec/javascripts/explore/components/ControlPanelSection_spec.jsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it } from 'mocha';
-import { shallow } from 'enzyme';
-import { Panel } from 'react-bootstrap';
-
-import InfoTooltipWithTrigger from
-  '../../../../src/components/InfoTooltipWithTrigger';
-
-import ControlPanelSection from
-  '../../../../src/explore/components/ControlPanelSection';
-
-const defaultProps = {
-  children: <div>a child element</div>,
-};
-
-const optionalProps = {
-  label: 'my label',
-  description: 'my description',
-  tooltip: 'my tooltip',
-};
-
-describe('ControlPanelSection', () => {
-  let wrapper;
-  let props;
-  it('is a valid element', () => {
-    expect(
-      React.isValidElement(<ControlPanelSection {...defaultProps} />),
-    ).to.equal(true);
-  });
-
-  it('renders a Panel component', () => {
-    wrapper = shallow(<ControlPanelSection {...defaultProps} />);
-    expect(wrapper.find(Panel)).to.have.length(1);
-  });
-
-  describe('with optional props', () => {
-    beforeEach(() => {
-      props = Object.assign(defaultProps, optionalProps);
-      wrapper = shallow(<ControlPanelSection {...props} />);
-    });
-
-    it('renders a label if present', () => {
-      expect(wrapper.find(Panel).dive().text()).to.contain('my label');
-    });
-
-    it('renders a InfoTooltipWithTrigger if label and tooltip is present', () => {
-      expect(wrapper.find(Panel).dive().find(InfoTooltipWithTrigger))
-        .to.have.length(1);
-    });
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx b/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx
deleted file mode 100644
index 64a657e1f7..0000000000
--- a/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { getFormDataFromControls, defaultControls }
-  from '../../../../src/explore/store';
-import {
-  ControlPanelsContainer,
-} from '../../../../src/explore/components/ControlPanelsContainer';
-import ControlPanelSection from '../../../../src/explore/components/ControlPanelSection';
-
-const defaultProps = {
-  datasource_type: 'table',
-  actions: {},
-  controls: defaultControls,
-  form_data: getFormDataFromControls(defaultControls),
-  isDatasourceMetaLoading: false,
-  exploreState: {},
-};
-
-describe('ControlPanelsContainer', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<ControlPanelsContainer {...defaultProps} />);
-  });
-
-  it('renders ControlPanelSections', () => {
-    expect(wrapper.find(ControlPanelSection)).to.have.lengthOf(6);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/ControlRow_spec.jsx b/superset/assets/spec/javascripts/explore/components/ControlRow_spec.jsx
deleted file mode 100644
index 118799eb8e..0000000000
--- a/superset/assets/spec/javascripts/explore/components/ControlRow_spec.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it } from 'mocha';
-import { shallow } from 'enzyme';
-import ControlSetRow from '../../../../src/explore/components/ControlRow';
-
-describe('ControlSetRow', () => {
-  it('renders a single row with one element', () => {
-    const wrapper = shallow(<ControlSetRow controls={[<a />]} />);
-    expect(wrapper.find('.row')).to.have.lengthOf(1);
-    expect(wrapper.find('.row').find('a')).to.have.lengthOf(1);
-  });
-  it('renders a single row with two elements', () => {
-    const wrapper = shallow(<ControlSetRow controls={[<a />, <a />]} />);
-    expect(wrapper.find('.row')).to.have.lengthOf(1);
-    expect(wrapper.find('.row').find('a')).to.have.lengthOf(2);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
deleted file mode 100644
index c8d1390850..0000000000
--- a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { Modal } from 'react-bootstrap';
-import DatasourceControl from '../../../../src/explore/components/controls/DatasourceControl';
-
-const defaultProps = {
-  name: 'datasource',
-  label: 'Datasource',
-  value: '1__table',
-  datasource: {
-    name: 'birth_names',
-    type: 'table',
-    uid: '1__table',
-    id: 1,
-    columns: [],
-    metrics: [],
-    database: {
-      backend: 'mysql',
-      name: 'main',
-    },
-  },
-  onChange: sinon.spy(),
-};
-
-describe('DatasourceControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<DatasourceControl {...defaultProps} />);
-  });
-
-  it('renders a Modal', () => {
-    expect(wrapper.find(Modal)).to.have.lengthOf(1);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/DateFilterControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/DateFilterControl_spec.jsx
deleted file mode 100644
index 0892d05abb..0000000000
--- a/superset/assets/spec/javascripts/explore/components/DateFilterControl_spec.jsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { Button } from 'react-bootstrap';
-
-import DateFilterControl from '../../../../src/explore/components/controls/DateFilterControl';
-import ControlHeader from '../../../../src/explore/components/ControlHeader';
-
-const defaultProps = {
-  animation: false,
-  name: 'date',
-  onChange: sinon.spy(),
-  value: '90 days ago',
-  label: 'date',
-};
-
-describe('DateFilterControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<DateFilterControl {...defaultProps} />);
-  });
-
-  it('renders a ControlHeader', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-  });
-  it('renders 3 Buttons', () => {
-    const label = wrapper.find('.label').first();
-    label.simulate('click');
-    setTimeout(() => {
-      expect(wrapper.find(Button)).to.have.length(3);
-    }, 10);
-  });
-  it('loads the right state', () => {
-    const label = wrapper.find('.label').first();
-    label.simulate('click');
-    setTimeout(() => {
-      expect(wrapper.state().num).to.equal('90');
-    }, 10);
-  });
-  it('sets now and closes', () => {
-    const label = wrapper.find('.now').first();
-    label.simulate('click');
-    setTimeout(() => {
-      expect(wrapper.state().free).to.equal('now');
-      expect(wrapper.find('.popover')).to.have.length(0);
-    }, 10);
-  });
-  it('renders 2 dimmed sections', () => {
-    const label = wrapper.find('.label').first();
-    label.simulate('click');
-    setTimeout(() => {
-      expect(wrapper.find(Button)).to.have.length(3);
-    }, 10);
-  });
-  it('opens and closes', () => {
-    const label = wrapper.find('.label').first();
-    label.simulate('click');
-    setTimeout(() => {
-      expect(wrapper.find('.popover')).to.have.length(1);
-      expect(wrapper.find('.ok')).first().simulate('click');
-      setTimeout(() => {
-        expect(wrapper.find('.popover')).to.have.length(0);
-      }, 10);
-    }, 10);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/FilterDefinitionOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/FilterDefinitionOption_spec.jsx
index 05e02b92a4..4797be45e0 100644
--- a/superset/assets/spec/javascripts/explore/components/FilterDefinitionOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/FilterDefinitionOption_spec.jsx
@@ -4,11 +4,11 @@ import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 
-import FilterDefinitionOption from '../../../../src/explore/components/FilterDefinitionOption';
+import FilterDefinitionOption from '../../../../src/controls/FilterDefinitionOption';
 import ColumnOption from '../../../../src/components/ColumnOption';
-import AdhocMetricStaticOption from '../../../../src/explore/components/AdhocMetricStaticOption';
-import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/explore/AdhocMetric';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetricStaticOption from '../../../../src/controls/AdhocMetricStaticOption';
+import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/controls/AdhocMetric';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const sumValueAdhocMetric = new AdhocMetric({
   expressionType: EXPRESSION_TYPES.SIMPLE,
diff --git a/superset/assets/spec/javascripts/explore/components/FixedOrMetricControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/FixedOrMetricControl_spec.jsx
deleted file mode 100644
index 97a685822c..0000000000
--- a/superset/assets/spec/javascripts/explore/components/FixedOrMetricControl_spec.jsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { OverlayTrigger } from 'react-bootstrap';
-
-import FixedOrMetricControl from
-  '../../../../src/explore/components/controls/FixedOrMetricControl';
-import SelectControl from
-  '../../../../src/explore/components/controls/SelectControl';
-import TextControl from
-  '../../../../src/explore/components/controls/TextControl';
-import ControlHeader from '../../../../src/explore/components/ControlHeader';
-
-const defaultProps = {
-  value: { },
-};
-
-describe('FixedOrMetricControl', () => {
-  let wrapper;
-  let inst;
-  beforeEach(() => {
-    wrapper = shallow(<FixedOrMetricControl {...defaultProps} />);
-    inst = wrapper.instance();
-  });
-
-  it('renders a OverlayTrigger', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-    expect(wrapper.find(OverlayTrigger)).to.have.length(1);
-  });
-
-  it('renders a TextControl and a SelectControl', () => {
-    const popOver = shallow(inst.renderPopover());
-    expect(popOver.find(TextControl)).to.have.lengthOf(1);
-    expect(popOver.find(SelectControl)).to.have.lengthOf(1);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx b/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
index 18129666cd..dfc94b5360 100644
--- a/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
@@ -4,10 +4,10 @@ import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 
-import MetricDefinitionOption from '../../../../src/explore/components/MetricDefinitionOption';
 import MetricOption from '../../../../src/components/MetricOption';
 import ColumnOption from '../../../../src/components/ColumnOption';
-import AggregateOption from '../../../../src/explore/components/AggregateOption';
+import MetricDefinitionOption from '../../../../src/controls/controls/MetricDefinitionOption';
+import AggregateOption from '../../../../src/controls/controls/AggregateOption';
 
 describe('MetricDefinitionOption', () => {
   it('renders a MetricOption given a saved metric', () => {
diff --git a/superset/assets/spec/javascripts/explore/components/MetricDefinitionValue_spec.jsx b/superset/assets/spec/javascripts/explore/components/MetricDefinitionValue_spec.jsx
index 896a5276e2..4ab3c1f441 100644
--- a/superset/assets/spec/javascripts/explore/components/MetricDefinitionValue_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/MetricDefinitionValue_spec.jsx
@@ -4,11 +4,11 @@ import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 
-import MetricDefinitionValue from '../../../../src/explore/components/MetricDefinitionValue';
+import MetricDefinitionValue from '../../../../src/controls/controls/MetricDefinitionValue';
 import MetricOption from '../../../../src/components/MetricOption';
-import AdhocMetricOption from '../../../../src/explore/components/AdhocMetricOption';
-import AdhocMetric from '../../../../src/explore/AdhocMetric';
-import { AGGREGATES } from '../../../../src/explore/constants';
+import AdhocMetricOption from '../../../../src/controls/controls/AdhocMetricOption';
+import AdhocMetric from '../../../../src/controls/AdhocMetric';
+import { AGGREGATES } from '../../../../src/controls/constants';
 
 const sumValueAdhocMetric = new AdhocMetric({
   column: { type: 'DOUBLE', column_name: 'value' },
diff --git a/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx
deleted file mode 100644
index 8afc9900bf..0000000000
--- a/superset/assets/spec/javascripts/explore/components/MetricsControl_spec.jsx
+++ /dev/null
@@ -1,313 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it } from 'mocha';
-import { shallow } from 'enzyme';
-
-import MetricsControl from '../../../../src/explore/components/controls/MetricsControl';
-import { AGGREGATES } from '../../../../src/explore/constants';
-import OnPasteSelect from '../../../../src/components/OnPasteSelect';
-import AdhocMetric, { EXPRESSION_TYPES } from '../../../../src/explore/AdhocMetric';
-
-const defaultProps = {
-  name: 'metrics',
-  label: 'Metrics',
-  value: undefined,
-  multi: true,
-  columns: [
-    { type: 'VARCHAR(255)', column_name: 'source' },
-    { type: 'VARCHAR(255)', column_name: 'target' },
-    { type: 'DOUBLE', column_name: 'value' },
-  ],
-  savedMetrics: [
-    { metric_name: 'sum__value', expression: 'SUM(energy_usage.value)' },
-    { metric_name: 'avg__value', expression: 'AVG(energy_usage.value)' },
-  ],
-  datasourceType: 'sqla',
-};
-
-function setup(overrides) {
-  const onChange = sinon.spy();
-  const props = {
-    onChange,
-    ...defaultProps,
-    ...overrides,
-  };
-  const wrapper = shallow(<MetricsControl {...props} />);
-  return { wrapper, onChange };
-}
-
-const valueColumn = { type: 'DOUBLE', column_name: 'value' };
-
-const sumValueAdhocMetric = new AdhocMetric({
-  column: valueColumn,
-  aggregate: AGGREGATES.SUM,
-  label: 'SUM(value)',
-});
-
-describe('MetricsControl', () => {
-
-  it('renders an OnPasteSelect', () => {
-    const { wrapper } = setup();
-    expect(wrapper.find(OnPasteSelect)).to.have.lengthOf(1);
-  });
-
-  describe('constructor', () => {
-
-    it('unifies options for the dropdown select with aggregates', () => {
-      const { wrapper } = setup();
-      expect(wrapper.state('options')).to.deep.equal([
-        { optionName: '_col_source', type: 'VARCHAR(255)', column_name: 'source' },
-        { optionName: '_col_target', type: 'VARCHAR(255)', column_name: 'target' },
-        { optionName: '_col_value', type: 'DOUBLE', column_name: 'value' },
-        ...Object.keys(AGGREGATES).map(
-          aggregate => ({ aggregate_name: aggregate, optionName: '_aggregate_' + aggregate }),
-        ),
-        { optionName: 'sum__value', metric_name: 'sum__value', expression: 'SUM(energy_usage.value)' },
-        { optionName: 'avg__value', metric_name: 'avg__value', expression: 'AVG(energy_usage.value)' },
-      ]);
-    });
-
-    it('coerces Adhoc Metrics from form data into instances of the AdhocMetric class and leaves saved metrics', () => {
-      const { wrapper } = setup({
-        value: [
-          {
-            expressionType: EXPRESSION_TYPES.SIMPLE,
-            column: { type: 'double', column_name: 'value' },
-            aggregate: AGGREGATES.SUM,
-            label: 'SUM(value)',
-            optionName: 'blahblahblah',
-          },
-          'avg__value',
-        ],
-      });
-
-      const adhocMetric = wrapper.state('value')[0];
-      expect(adhocMetric instanceof AdhocMetric).to.be.true;
-      expect(adhocMetric.optionName.length).to.be.above(10);
-      expect(wrapper.state('value')).to.deep.equal([
-        {
-          expressionType: EXPRESSION_TYPES.SIMPLE,
-          column: { type: 'double', column_name: 'value' },
-          aggregate: AGGREGATES.SUM,
-          fromFormData: true,
-          label: 'SUM(value)',
-          hasCustomLabel: false,
-          optionName: 'blahblahblah',
-          sqlExpression: null,
-        },
-        'avg__value',
-      ]);
-    });
-
-  });
-
-  describe('onChange', () => {
-
-    it('handles saved metrics being selected', () => {
-      const { wrapper, onChange } = setup();
-      const select = wrapper.find(OnPasteSelect);
-      select.simulate('change', [{ metric_name: 'sum__value' }]);
-      expect(onChange.lastCall.args).to.deep.equal([['sum__value']]);
-    });
-
-    it('handles columns being selected', () => {
-      const { wrapper, onChange } = setup();
-      const select = wrapper.find(OnPasteSelect);
-      select.simulate('change', [valueColumn]);
-
-      const adhocMetric = onChange.lastCall.args[0][0];
-      expect(adhocMetric instanceof AdhocMetric).to.be.true;
-      expect(onChange.lastCall.args).to.deep.equal([[{
-        expressionType: EXPRESSION_TYPES.SIMPLE,
-        column: valueColumn,
-        aggregate: AGGREGATES.SUM,
-        label: 'SUM(value)',
-        fromFormData: false,
-        hasCustomLabel: false,
-        optionName: adhocMetric.optionName,
-        sqlExpression: null,
-      }]]);
-    });
-
-    it('handles aggregates being selected', () => {
-      const { wrapper, onChange } = setup();
-      const select = wrapper.find(OnPasteSelect);
-
-      // mock out the Select ref
-      const setInputSpy = sinon.spy();
-      const handleInputSpy = sinon.spy();
-      wrapper.instance().select = {
-        setInputValue: setInputSpy,
-        handleInputChange: handleInputSpy,
-        input: { input: {} },
-      };
-
-      select.simulate('change', [{ aggregate_name: 'SUM', optionName: 'SUM' }]);
-
-      expect(setInputSpy.calledWith('SUM()')).to.be.true;
-      expect(handleInputSpy.calledWith({ target: { value: 'SUM()' } })).to.be.true;
-      expect(onChange.lastCall.args).to.deep.equal([[]]);
-    });
-
-    it('preserves existing selected AdhocMetrics', () => {
-      const { wrapper, onChange } = setup();
-      const select = wrapper.find(OnPasteSelect);
-      select.simulate('change', [{ metric_name: 'sum__value' }, sumValueAdhocMetric]);
-      expect(onChange.lastCall.args).to.deep.equal([['sum__value', sumValueAdhocMetric]]);
-    });
-  });
-
-  describe('onMetricEdit', () => {
-    it('accepts an edited metric from an AdhocMetricEditPopover', () => {
-      const { wrapper, onChange } = setup({
-        value: [sumValueAdhocMetric],
-      });
-
-      const editedMetric = sumValueAdhocMetric.duplicateWith({ aggregate: AGGREGATES.AVG });
-      wrapper.instance().onMetricEdit(editedMetric);
-
-      expect(onChange.lastCall.args).to.deep.equal([[
-        editedMetric,
-      ]]);
-    });
-  });
-
-  describe('checkIfAggregateInInput', () => {
-    it('handles an aggregate in the input', () => {
-      const { wrapper } = setup();
-
-      expect(wrapper.state('aggregateInInput')).to.be.null;
-      wrapper.instance().checkIfAggregateInInput('AVG(');
-      expect(wrapper.state('aggregateInInput')).to.equal(AGGREGATES.AVG);
-    });
-
-    it('handles no aggregate in the input', () => {
-      const { wrapper } = setup();
-
-      expect(wrapper.state('aggregateInInput')).to.be.null;
-      wrapper.instance().checkIfAggregateInInput('colu');
-      expect(wrapper.state('aggregateInInput')).to.be.null;
-    });
-  });
-
-  describe('option filter', () => {
-    it('includes user defined metrics', () => {
-      const { wrapper } = setup({ datasourceType: 'druid' });
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'a_metric',
-          optionName: 'a_metric',
-          expression: 'SUM(FANCY(metric))',
-        },
-        'a',
-      )).to.be.true;
-    });
-
-    it('includes auto generated avg metrics for druid', () => {
-      const { wrapper } = setup({ datasourceType: 'druid' });
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'avg__metric',
-          optionName: 'avg__metric',
-          expression: 'AVG(metric)',
-        },
-        'a',
-      )).to.be.true;
-    });
-
-    it('includes columns and aggregates', () => {
-      const { wrapper } = setup();
-
-      expect(!!wrapper.instance().selectFilterOption(
-        { type: 'VARCHAR(255)', column_name: 'source', optionName: '_col_source' },
-        'sou',
-      )).to.be.true;
-
-      expect(!!wrapper.instance().selectFilterOption(
-        { aggregate_name: 'AVG', optionName: '_aggregate_AVG' },
-        'av',
-      )).to.be.true;
-    });
-
-    it('includes columns based on verbose_name', () => {
-      const { wrapper } = setup();
-
-      expect(!!wrapper.instance().selectFilterOption(
-        { metric_name: 'sum__num', verbose_name: 'babies', optionName: '_col_sum_num' },
-        'bab',
-      )).to.be.true;
-    });
-
-    it('excludes auto generated avg metrics for sqla', () => {
-      const { wrapper } = setup();
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'avg__metric',
-          optionName: 'avg__metric',
-          expression: 'AVG(metric)',
-        },
-        'a',
-      )).to.be.false;
-    });
-
-    it('includes custom made simple saved metrics', () => {
-      const { wrapper } = setup();
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'my_fancy_sum_metric',
-          optionName: 'my_fancy_sum_metric',
-          expression: 'SUM(value)',
-        },
-        'sum',
-      )).to.be.true;
-    });
-
-    it('excludes auto generated metrics', () => {
-      const { wrapper } = setup();
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'sum__value',
-          optionName: 'sum__value',
-          expression: 'SUM(value)',
-        },
-        'sum',
-      )).to.be.false;
-
-      expect(!!wrapper.instance().selectFilterOption(
-        {
-          metric_name: 'sum__value',
-          optionName: 'sum__value',
-          expression: 'SUM("table"."value")',
-        },
-        'sum',
-      )).to.be.false;
-    });
-
-    it('filters out metrics if the input begins with an aggregate', () => {
-      const { wrapper } = setup();
-      wrapper.setState({ aggregateInInput: true });
-
-      expect(!!wrapper.instance().selectFilterOption(
-        { metric_name: 'metric', expression: 'SUM(FANCY(metric))' },
-        'SUM(',
-      )).to.be.false;
-    });
-
-    it('includes columns if the input begins with an aggregate', () => {
-      const { wrapper } = setup();
-      wrapper.setState({ aggregateInInput: true });
-
-      expect(!!wrapper.instance().selectFilterOption(
-        { type: 'DOUBLE', column_name: 'value' },
-        'SUM(',
-      )).to.be.true;
-    });
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/SelectControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/SelectControl_spec.jsx
deleted file mode 100644
index 38194e5cba..0000000000
--- a/superset/assets/spec/javascripts/explore/components/SelectControl_spec.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import Select, { Creatable } from 'react-select';
-import VirtualizedSelect from 'react-virtualized-select';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import OnPasteSelect from '../../../../src/components/OnPasteSelect';
-import VirtualizedRendererWrap from '../../../../src/components/VirtualizedRendererWrap';
-import SelectControl from '../../../../src/explore/components/controls/SelectControl';
-
-const defaultProps = {
-  choices: [['1 year ago', '1 year ago'], ['today', 'today']],
-  name: 'row_limit',
-  label: 'Row Limit',
-  onChange: sinon.spy(),
-};
-
-const options = [
-  { value: '1 year ago', label: '1 year ago' },
-  { value: 'today', label: 'today' },
-];
-
-describe('SelectControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<SelectControl {...defaultProps} />);
-  });
-
-  it('renders an OnPasteSelect', () => {
-    expect(wrapper.find(OnPasteSelect)).to.have.lengthOf(1);
-  });
-
-  it('calls onChange when toggled', () => {
-    const select = wrapper.find(OnPasteSelect);
-    select.simulate('change', { value: 50 });
-    expect(defaultProps.onChange.calledWith(50)).to.be.true;
-  });
-
-  it('passes VirtualizedSelect as selectWrap', () => {
-    const select = wrapper.find(OnPasteSelect);
-    expect(select.props().selectWrap).to.equal(VirtualizedSelect);
-  });
-
-  it('passes Creatable as selectComponent when freeForm=true', () => {
-    wrapper = shallow(<SelectControl {...defaultProps} freeForm />);
-    const select = wrapper.find(OnPasteSelect);
-    expect(select.props().selectComponent).to.equal(Creatable);
-  });
-
-  it('passes Select as selectComponent when freeForm=false', () => {
-    const select = wrapper.find(OnPasteSelect);
-    expect(select.props().selectComponent).to.equal(Select);
-  });
-
-  it('wraps optionRenderer in a VirtualizedRendererWrap', () => {
-    const select = wrapper.find(OnPasteSelect);
-    const defaultOptionRenderer = SelectControl.defaultProps.optionRenderer;
-    const wrappedRenderer = VirtualizedRendererWrap(defaultOptionRenderer);
-    expect(select.props().optionRenderer).to.be.a('Function');
-    // different instances of wrapper with same inner renderer are unequal
-    expect(select.props().optionRenderer.name).to.equal(wrappedRenderer.name);
-  });
-
-  describe('getOptions', () => {
-    it('returns the correct options', () => {
-      expect(wrapper.instance().getOptions(defaultProps)).to.deep.equal(options);
-    });
-
-    it('returns the correct options when freeform is set to true', () => {
-      const freeFormProps = Object.assign(defaultProps, {
-        choices: [],
-        freeForm: true,
-        value: ['one', 'two'],
-      });
-      const newOptions = [
-        { value: 'one', label: 'one' },
-        { value: 'two', label: 'two' },
-      ];
-      expect(wrapper.instance().getOptions(freeFormProps)).to.deep.equal(newOptions);
-    });
-  });
-
-  describe('componentWillReceiveProps', () => {
-    it('sets state.options if props.choices has changed', () => {
-      const updatedOptions = [
-        { value: 'three', label: 'three' },
-        { value: 'four', label: 'four' },
-      ];
-      const newProps = {
-        choices: [['three', 'three'], ['four', 'four']],
-        name: 'name',
-        freeForm: false,
-        value: null,
-      };
-      wrapper.setProps(newProps);
-      expect(wrapper.state().options).to.deep.equal(updatedOptions);
-    });
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/TextArea_spec.jsx b/superset/assets/spec/javascripts/explore/components/TextArea_spec.jsx
index c1253f0933..2bbecd4ef5 100644
--- a/superset/assets/spec/javascripts/explore/components/TextArea_spec.jsx
+++ b/superset/assets/spec/javascripts/explore/components/TextArea_spec.jsx
@@ -7,7 +7,7 @@ import { describe, it, beforeEach } from 'mocha';
 import { shallow } from 'enzyme';
 import AceEditor from 'react-ace';
 
-import TextAreaControl from '../../../../src/explore/components/controls/TextAreaControl';
+import TextAreaControl from '../../../../src/controls/controls/TextAreaControl';
 
 const defaultProps = {
   name: 'x_axis_label',
diff --git a/superset/assets/spec/javascripts/explore/components/TimeSeriesColumnControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/TimeSeriesColumnControl_spec.jsx
deleted file mode 100644
index 7e28ab0d8a..0000000000
--- a/superset/assets/spec/javascripts/explore/components/TimeSeriesColumnControl_spec.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import { FormControl, OverlayTrigger } from 'react-bootstrap';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-
-import TimeSeriesColumnControl from '../../../../src/explore/components/controls/TimeSeriesColumnControl';
-
-const defaultProps = {
-  name: 'x_axis_label',
-  label: 'X Axis Label',
-  onChange: sinon.spy(),
-};
-
-describe('SelectControl', () => {
-  let wrapper;
-  let inst;
-  beforeEach(() => {
-    wrapper = shallow(<TimeSeriesColumnControl {...defaultProps} />);
-    inst = wrapper.instance();
-  });
-
-  it('renders an OverlayTrigger', () => {
-    expect(wrapper.find(OverlayTrigger)).to.have.lengthOf(1);
-  });
-
-  it('renders an Popover', () => {
-    const popOver = shallow(inst.renderPopover());
-    expect(popOver.find(FormControl)).to.have.lengthOf(3);
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/ViewportControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/ViewportControl_spec.jsx
deleted file mode 100644
index a840e7cbb3..0000000000
--- a/superset/assets/spec/javascripts/explore/components/ViewportControl_spec.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/* eslint-disable no-unused-expressions */
-import React from 'react';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { OverlayTrigger, Label } from 'react-bootstrap';
-
-import ViewportControl from
-  '../../../../src/explore/components/controls/ViewportControl';
-import TextControl from
-  '../../../../src/explore/components/controls/TextControl';
-import ControlHeader from '../../../../src/explore/components/ControlHeader';
-
-const defaultProps = {
-  value: {
-    longitude: 6.85236157047845,
-    latitude: 31.222656842808707,
-    zoom: 1,
-    bearing: 0,
-    pitch: 0,
-  },
-};
-
-describe('ViewportControl', () => {
-  let wrapper;
-  let inst;
-  beforeEach(() => {
-    wrapper = shallow(<ViewportControl {...defaultProps} />);
-    inst = wrapper.instance();
-  });
-
-  it('renders a OverlayTrigger', () => {
-    const controlHeader = wrapper.find(ControlHeader);
-    expect(controlHeader).to.have.lengthOf(1);
-    expect(wrapper.find(OverlayTrigger)).to.have.length(1);
-  });
-
-  it('renders a Popover with 5 TextControl', () => {
-    const popOver = shallow(inst.renderPopover());
-    expect(popOver.find(TextControl)).to.have.lengthOf(5);
-  });
-
-  it('renders a summary in the label', () => {
-    expect(wrapper.find(Label).first().render().text()).to.equal('6° 51\' 8.50" | 31° 13\' 21.56"');
-  });
-});
diff --git a/superset/assets/spec/javascripts/explore/components/VizTypeControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/VizTypeControl_spec.jsx
deleted file mode 100644
index 03b73c9eae..0000000000
--- a/superset/assets/spec/javascripts/explore/components/VizTypeControl_spec.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import sinon from 'sinon';
-import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
-import { shallow } from 'enzyme';
-import { Modal } from 'react-bootstrap';
-import VizTypeControl from '../../../../src/explore/components/controls/VizTypeControl';
-
-const defaultProps = {
-  name: 'viz_type',
-  label: 'Visualization Type',
-  value: 'table',
-  onChange: sinon.spy(),
-};
-
-describe('VizTypeControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<VizTypeControl {...defaultProps} />);
-  });
-
-  it('renders a Modal', () => {
-    expect(wrapper.find(Modal)).to.have.lengthOf(1);
-  });
-
-  it('calls onChange when toggled', () => {
-    const select = wrapper.find('.viztype-selector-container').first();
-    select.simulate('click');
-    expect(defaultProps.onChange.called).to.equal(true);
-  });
-  it('filters images based on text input', () => {
-    expect(wrapper.find('img').length).to.be.above(20);
-    wrapper.setState({ filter: 'time' });
-    expect(wrapper.find('img').length).to.be.below(10);
-  });
-});
diff --git a/superset/assets/src/explore/AdhocFilter.js b/superset/assets/src/explore/AdhocFilter.js
deleted file mode 100644
index dfaef55209..0000000000
--- a/superset/assets/src/explore/AdhocFilter.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import { MULTI_OPERATORS } from './constants';
-
-export const EXPRESSION_TYPES = {
-  SIMPLE: 'SIMPLE',
-  SQL: 'SQL',
-};
-
-export const CLAUSES = {
-  HAVING: 'HAVING',
-  WHERE: 'WHERE',
-};
-
-const OPERATORS_TO_SQL = {
-  '==': '=',
-  '!=': '<>',
-  '>': '>',
-  '<': '<',
-  '>=': '>=',
-  '<=': '<=',
-  in: 'in',
-  'not in': 'not in',
-  LIKE: 'like',
-  regex: 'regex',
-};
-
-function translateToSql(adhocMetric, { useSimple } = {}) {
-  if (adhocMetric.expressionType === EXPRESSION_TYPES.SIMPLE || useSimple) {
-    const isMulti = MULTI_OPERATORS.indexOf(adhocMetric.operator) >= 0;
-    const subject = adhocMetric.subject;
-    const operator = OPERATORS_TO_SQL[adhocMetric.operator];
-    const comparator = isMulti ? adhocMetric.comparator.join("','") : adhocMetric.comparator;
-    return `${subject} ${operator} ${isMulti ? '(\'' : ''}${comparator}${isMulti ? '\')' : ''}`;
-  } else if (adhocMetric.expressionType === EXPRESSION_TYPES.SQL) {
-    return adhocMetric.sqlExpression;
-  }
-  return '';
-}
-
-export default class AdhocFilter {
-  constructor(adhocFilter) {
-    this.expressionType = adhocFilter.expressionType || EXPRESSION_TYPES.SIMPLE;
-    if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
-      this.subject = adhocFilter.subject;
-      this.operator = adhocFilter.operator;
-      this.comparator = adhocFilter.comparator;
-      this.clause = adhocFilter.clause;
-      this.sqlExpression = null;
-    } else if (this.expressionType === EXPRESSION_TYPES.SQL) {
-      this.sqlExpression = typeof adhocFilter.sqlExpression === 'string' ?
-        adhocFilter.sqlExpression :
-        translateToSql(adhocFilter, { useSimple: true });
-      this.clause = adhocFilter.clause;
-      this.subject = null;
-      this.operator = null;
-      this.comparator = null;
-    }
-    this.fromFormData = !!adhocFilter.filterOptionName;
-
-    this.filterOptionName = adhocFilter.filterOptionName ||
-      `filter_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
-  }
-
-  duplicateWith(nextFields) {
-    return new AdhocFilter({
-      ...this,
-      expressionType: this.expressionType,
-      subject: this.subject,
-      operator: this.operator,
-      clause: this.clause,
-      sqlExpression: this.sqlExpression,
-      fromFormData: this.fromFormData,
-      filterOptionName: this.filterOptionName,
-      ...nextFields,
-    });
-  }
-
-  equals(adhocFilter) {
-    return adhocFilter.expressionType === this.expressionType &&
-      adhocFilter.sqlExpression === this.sqlExpression &&
-      adhocFilter.operator === this.operator &&
-      adhocFilter.comparator === this.comparator &&
-      adhocFilter.subject === this.subject;
-  }
-
-  isValid() {
-    if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
-      return !!(
-        this.operator &&
-        this.subject &&
-        this.comparator &&
-        this.comparator.length > 0 &&
-        this.clause
-      );
-    } else if (this.expressionType === EXPRESSION_TYPES.SQL) {
-      return !!(this.sqlExpression && this.clause);
-    }
-    return false;
-  }
-
-  getDefaultLabel() {
-    const label = this.translateToSql();
-    return label.length < 43 ?
-      label :
-      label.substring(0, 40) + '...';
-  }
-
-  translateToSql() {
-    return translateToSql(this);
-  }
-}
diff --git a/superset/assets/src/explore/AdhocMetric.js b/superset/assets/src/explore/AdhocMetric.js
deleted file mode 100644
index e069fd7359..0000000000
--- a/superset/assets/src/explore/AdhocMetric.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import { sqlaAutoGeneratedMetricRegex } from './constants';
-
-export const EXPRESSION_TYPES = {
-  SIMPLE: 'SIMPLE',
-  SQL: 'SQL',
-};
-
-function inferSqlExpressionColumn(adhocMetric) {
-  if (adhocMetric.sqlExpression && sqlaAutoGeneratedMetricRegex.test(adhocMetric.sqlExpression)) {
-    const indexFirstCloseParen = adhocMetric.sqlExpression.indexOf(')');
-    const indexPairedOpenParen =
-      adhocMetric.sqlExpression.substring(0, indexFirstCloseParen).lastIndexOf('(');
-    if (indexFirstCloseParen > 0 && indexPairedOpenParen > 0) {
-      return adhocMetric.sqlExpression.substring(indexPairedOpenParen + 1, indexFirstCloseParen);
-    }
-  }
-  return null;
-}
-
-function inferSqlExpressionAggregate(adhocMetric) {
-  if (adhocMetric.sqlExpression && sqlaAutoGeneratedMetricRegex.test(adhocMetric.sqlExpression)) {
-    const indexFirstOpenParen = adhocMetric.sqlExpression.indexOf('(');
-    if (indexFirstOpenParen > 0) {
-      return adhocMetric.sqlExpression.substring(0, indexFirstOpenParen);
-    }
-  }
-  return null;
-}
-
-export default class AdhocMetric {
-  constructor(adhocMetric) {
-    this.expressionType = adhocMetric.expressionType || EXPRESSION_TYPES.SIMPLE;
-    if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
-      // try to be clever in the case of transitioning from Sql expression back to simple expression
-      const inferredColumn = inferSqlExpressionColumn(adhocMetric);
-      this.column = adhocMetric.column || (inferredColumn && { column_name: inferredColumn });
-      this.aggregate = adhocMetric.aggregate || inferSqlExpressionAggregate(adhocMetric);
-      this.sqlExpression = null;
-    } else if (this.expressionType === EXPRESSION_TYPES.SQL) {
-      this.sqlExpression = adhocMetric.sqlExpression;
-      this.column = null;
-      this.aggregate = null;
-    }
-    this.hasCustomLabel = !!(adhocMetric.hasCustomLabel && adhocMetric.label);
-    this.fromFormData = !!adhocMetric.optionName;
-    this.label = this.hasCustomLabel ? adhocMetric.label : this.getDefaultLabel();
-
-    this.optionName = adhocMetric.optionName ||
-      `metric_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`;
-  }
-
-  getDefaultLabel() {
-    const label = this.translateToSql();
-    return label.length < 43 ?
-      label :
-      label.substring(0, 40) + '...';
-  }
-
-  translateToSql() {
-    if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
-      return `${this.aggregate || ''}(${(this.column && this.column.column_name) || ''})`;
-    } else if (this.expressionType === EXPRESSION_TYPES.SQL) {
-      return this.sqlExpression;
-    }
-    return '';
-  }
-
-  duplicateWith(nextFields) {
-    return new AdhocMetric({
-      ...this,
-      ...nextFields,
-    });
-  }
-
-  equals(adhocMetric) {
-    return adhocMetric.label === this.label &&
-      adhocMetric.expressionType === this.expressionType &&
-      adhocMetric.sqlExpression === this.sqlExpression &&
-      adhocMetric.aggregate === this.aggregate &&
-      (
-        (adhocMetric.column && adhocMetric.column.column_name) ===
-        (this.column && this.column.column_name)
-      );
-  }
-
-  isValid() {
-    if (this.expressionType === EXPRESSION_TYPES.SIMPLE) {
-      return !!(this.column && this.aggregate);
-    } else if (this.expressionType === EXPRESSION_TYPES.SQL) {
-      return !!(this.sqlExpression);
-    }
-    return false;
-  }
-
-  inferSqlExpressionAggregate() {
-    return inferSqlExpressionAggregate(this);
-  }
-
-  inferSqlExpressionColumn() {
-    return inferSqlExpressionColumn(this);
-  }
-}
diff --git a/superset/assets/src/explore/components/AdhocFilterEditPopover.jsx b/superset/assets/src/explore/components/AdhocFilterEditPopover.jsx
deleted file mode 100644
index c8c0726cf9..0000000000
--- a/superset/assets/src/explore/components/AdhocFilterEditPopover.jsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
-
-import columnType from '../propTypes/columnType';
-import adhocMetricType from '../propTypes/adhocMetricType';
-import AdhocFilter, { EXPRESSION_TYPES } from '../AdhocFilter';
-import AdhocFilterEditPopoverSimpleTabContent from './AdhocFilterEditPopoverSimpleTabContent';
-import AdhocFilterEditPopoverSqlTabContent from './AdhocFilterEditPopoverSqlTabContent';
-
-const propTypes = {
-  adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
-  onChange: PropTypes.func.isRequired,
-  onClose: PropTypes.func.isRequired,
-  onResize: PropTypes.func.isRequired,
-  options: PropTypes.arrayOf(PropTypes.oneOfType([
-    columnType,
-    PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
-    adhocMetricType,
-  ])).isRequired,
-  datasource: PropTypes.object,
-};
-
-const startingWidth = 300;
-const startingHeight = 190;
-
-export default class AdhocFilterEditPopover extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onSave = this.onSave.bind(this);
-    this.onDragDown = this.onDragDown.bind(this);
-    this.onMouseMove = this.onMouseMove.bind(this);
-    this.onMouseUp = this.onMouseUp.bind(this);
-    this.onAdhocFilterChange = this.onAdhocFilterChange.bind(this);
-    this.adjustHeight = this.adjustHeight.bind(this);
-
-    this.state = {
-      adhocFilter: this.props.adhocFilter,
-      width: startingWidth,
-      height: startingHeight,
-    };
-  }
-
-  componentDidMount() {
-    document.addEventListener('mouseup', this.onMouseUp);
-  }
-
-  componentWillUnmount() {
-    document.removeEventListener('mouseup', this.onMouseUp);
-    document.removeEventListener('mousemove', this.onMouseMove);
-  }
-
-  onAdhocFilterChange(adhocFilter) {
-    this.setState({ adhocFilter });
-  }
-
-  onSave() {
-    this.props.onChange(this.state.adhocFilter);
-    this.props.onClose();
-  }
-
-  onDragDown(e) {
-    this.dragStartX = e.clientX;
-    this.dragStartY = e.clientY;
-    this.dragStartWidth = this.state.width;
-    this.dragStartHeight = this.state.height;
-    document.addEventListener('mousemove', this.onMouseMove);
-  }
-
-  onMouseMove(e) {
-    this.props.onResize();
-    this.setState({
-      width: Math.max(this.dragStartWidth + (e.clientX - this.dragStartX), startingWidth),
-      height: Math.max(this.dragStartHeight + (e.clientY - this.dragStartY) * 2, startingHeight),
-    });
-  }
-
-  onMouseUp() {
-    document.removeEventListener('mousemove', this.onMouseMove);
-  }
-
-  adjustHeight(heightDifference) {
-    this.setState(state => ({ height: state.height + heightDifference }));
-  }
-
-  render() {
-    const {
-      adhocFilter: propsAdhocFilter,
-      options,
-      onChange,
-      onClose,
-      onResize,
-      datasource,
-      ...popoverProps
-    } = this.props;
-
-    const { adhocFilter } = this.state;
-
-    const stateIsValid = adhocFilter.isValid();
-    const hasUnsavedChanges = !adhocFilter.equals(propsAdhocFilter);
-
-    return (
-      <Popover
-        id="filter-edit-popover"
-        {...popoverProps}
-      >
-        <Tabs
-          id="adhoc-filter-edit-tabs"
-          defaultActiveKey={adhocFilter.expressionType}
-          className="adhoc-filter-edit-tabs"
-          style={{ height: this.state.height, width: this.state.width }}
-        >
-          <Tab
-            className="adhoc-filter-edit-tab"
-            eventKey={EXPRESSION_TYPES.SIMPLE}
-            title="Simple"
-          >
-            <AdhocFilterEditPopoverSimpleTabContent
-              adhocFilter={this.state.adhocFilter}
-              onChange={this.onAdhocFilterChange}
-              options={this.props.options}
-              datasource={this.props.datasource}
-              onHeightChange={this.adjustHeight}
-            />
-          </Tab>
-          <Tab
-            className="adhoc-filter-edit-tab"
-            eventKey={EXPRESSION_TYPES.SQL}
-            title="Custom SQL"
-          >
-            {
-              (!this.props.datasource || this.props.datasource.type !== 'druid') ?
-                <AdhocFilterEditPopoverSqlTabContent
-                  adhocFilter={this.state.adhocFilter}
-                  onChange={this.onAdhocFilterChange}
-                  options={this.props.options}
-                  height={this.state.height}
-                /> :
-                <div className="custom-sql-disabled-message">
-                  Custom SQL Filters are not available on druid datasources
-                </div>
-            }
-          </Tab>
-        </Tabs>
-        <div>
-          <Button
-            disabled={!stateIsValid}
-            bsStyle={(hasUnsavedChanges && stateIsValid) ? 'primary' : 'default'}
-            bsSize="small"
-            className="m-r-5"
-            onClick={this.onSave}
-          >
-            Save
-          </Button>
-          <Button bsSize="small" onClick={this.props.onClose}>Close</Button>
-          <i onMouseDown={this.onDragDown} className="glyphicon glyphicon-resize-full edit-popover-resize" />
-        </div>
-      </Popover>
-    );
-  }
-}
-AdhocFilterEditPopover.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx b/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
deleted file mode 100644
index 222772a464..0000000000
--- a/superset/assets/src/explore/components/AdhocFilterEditPopoverSimpleTabContent.jsx
+++ /dev/null
@@ -1,293 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FormGroup } from 'react-bootstrap';
-import VirtualizedSelect from 'react-virtualized-select';
-
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../AdhocFilter';
-import adhocMetricType from '../propTypes/adhocMetricType';
-import columnType from '../propTypes/columnType';
-import { t } from '../../locales';
-import {
-  OPERATORS,
-  TABLE_ONLY_OPERATORS,
-  DRUID_ONLY_OPERATORS,
-  HAVING_OPERATORS,
-  MULTI_OPERATORS,
-} from '../constants';
-import FilterDefinitionOption from './FilterDefinitionOption';
-import OnPasteSelect from '../../components/OnPasteSelect';
-import SelectControl from './controls/SelectControl';
-import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
-
-const $ = require('jquery');
-
-const propTypes = {
-  adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
-  onChange: PropTypes.func.isRequired,
-  options: PropTypes.arrayOf(PropTypes.oneOfType([
-    columnType,
-    PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
-    adhocMetricType,
-  ])).isRequired,
-  onHeightChange: PropTypes.func.isRequired,
-  datasource: PropTypes.object,
-};
-
-const defaultProps = {
-  datasource: {},
-};
-
-function translateOperator(operator) {
-  if (operator === OPERATORS['==']) {
-    return 'equals';
-  } else if (operator === OPERATORS['!=']) {
-    return 'not equal to';
-  } else if (operator === OPERATORS.LIKE) {
-    return 'like';
-  }
-  return operator;
-}
-
-const SINGLE_LINE_SELECT_CONTROL_HEIGHT = 30;
-
-export default class AdhocFilterEditPopoverSimpleTabContent extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onSubjectChange = this.onSubjectChange.bind(this);
-    this.onOperatorChange = this.onOperatorChange.bind(this);
-    this.onComparatorChange = this.onComparatorChange.bind(this);
-    this.onInputComparatorChange = this.onInputComparatorChange.bind(this);
-    this.isOperatorRelevant = this.isOperatorRelevant.bind(this);
-    this.refreshComparatorSuggestions = this.refreshComparatorSuggestions.bind(this);
-    this.multiComparatorRef = this.multiComparatorRef.bind(this);
-
-    this.state = {
-      suggestions: [],
-      multiComparatorHeight: SINGLE_LINE_SELECT_CONTROL_HEIGHT,
-    };
-
-    this.selectProps = {
-      multi: false,
-      name: 'select-column',
-      labelKey: 'label',
-      autosize: false,
-      clearable: false,
-      selectWrap: VirtualizedSelect,
-    };
-  }
-
-  componentWillMount() {
-    this.refreshComparatorSuggestions();
-  }
-
-  componentDidMount() {
-    this.handleMultiComparatorInputHeightChange();
-  }
-
-  componentDidUpdate(prevProps) {
-    if (prevProps.adhocFilter.subject !== this.props.adhocFilter.subject) {
-      this.refreshComparatorSuggestions();
-    }
-    this.handleMultiComparatorInputHeightChange();
-  }
-
-  onSubjectChange(option) {
-    let subject;
-    let clause;
-    // infer the new clause based on what subject was selected.
-    if (option && option.column_name) {
-      subject = option.column_name;
-      clause = CLAUSES.WHERE;
-    } else if (option && (option.saved_metric_name || option.label)) {
-      subject = option.saved_metric_name || option.label;
-      clause = CLAUSES.HAVING;
-    }
-    this.props.onChange(this.props.adhocFilter.duplicateWith({
-      subject,
-      clause,
-      expressionType: EXPRESSION_TYPES.SIMPLE,
-    }));
-  }
-
-  onOperatorChange(operator) {
-    const currentComparator = this.props.adhocFilter.comparator;
-    let newComparator;
-    // convert between list of comparators and individual comparators
-    // (e.g. `in ('North America', 'Africa')` to `== 'North America'`)
-    if (MULTI_OPERATORS.indexOf(operator.operator) >= 0) {
-      newComparator = Array.isArray(currentComparator) ?
-        currentComparator :
-        [currentComparator].filter(element => element);
-    } else {
-      newComparator = Array.isArray(currentComparator) ? currentComparator[0] : currentComparator;
-    }
-    this.props.onChange(this.props.adhocFilter.duplicateWith({
-      operator: operator && operator.operator,
-      comparator: newComparator,
-      expressionType: EXPRESSION_TYPES.SIMPLE,
-    }));
-  }
-
-  onInputComparatorChange(event) {
-    this.onComparatorChange(event.target.value);
-  }
-
-  onComparatorChange(comparator) {
-    this.props.onChange(this.props.adhocFilter.duplicateWith({
-      comparator,
-      expressionType: EXPRESSION_TYPES.SIMPLE,
-    }));
-  }
-
-  handleMultiComparatorInputHeightChange() {
-    if (this.multiComparatorComponent) {
-      /* eslint-disable no-underscore-dangle */
-      const multiComparatorDOMNode = this.multiComparatorComponent._selectRef &&
-        this.multiComparatorComponent._selectRef.select &&
-        this.multiComparatorComponent._selectRef.select.control;
-      if (multiComparatorDOMNode) {
-        if (multiComparatorDOMNode.clientHeight !== this.state.multiComparatorHeight) {
-          this.props.onHeightChange((
-            multiComparatorDOMNode.clientHeight - this.state.multiComparatorHeight
-          ));
-          this.setState({ multiComparatorHeight: multiComparatorDOMNode.clientHeight });
-        }
-      }
-    }
-  }
-
-  refreshComparatorSuggestions() {
-    const datasource = this.props.datasource;
-    const col = this.props.adhocFilter.subject;
-    const having = this.props.adhocFilter.clause === CLAUSES.HAVING;
-
-    if (col && datasource && datasource.filter_select && !having) {
-      if (this.state.activeRequest) {
-        this.state.activeRequest.abort();
-      }
-      this.setState({
-        activeRequest: $.ajax({
-          type: 'GET',
-          url: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`,
-          success: data => this.setState({ suggestions: data, activeRequest: null }),
-        }),
-      });
-    }
-  }
-
-  isOperatorRelevant(operator) {
-    return !(
-      (this.props.datasource.type === 'druid' && TABLE_ONLY_OPERATORS.indexOf(operator) >= 0) ||
-      (this.props.datasource.type === 'table' && DRUID_ONLY_OPERATORS.indexOf(operator) >= 0) ||
-      (
-        this.props.adhocFilter.clause === CLAUSES.HAVING &&
-        HAVING_OPERATORS.indexOf(operator) === -1
-      )
-    );
-  }
-
-  focusComparator(ref) {
-    if (ref) {
-      ref.focus();
-    }
-  }
-
-  multiComparatorRef(ref) {
-    if (ref) {
-      this.multiComparatorComponent = ref;
-    }
-  }
-
-  render() {
-    const { adhocFilter, options, datasource } = this.props;
-
-    let subjectSelectProps = {
-      value: adhocFilter.subject ? { value: adhocFilter.subject } : undefined,
-      onChange: this.onSubjectChange,
-      optionRenderer: VirtualizedRendererWrap(option => (
-        <FilterDefinitionOption option={option} />
-      )),
-      valueRenderer: option => <span>{option.value}</span>,
-      valueKey: 'filterOptionName',
-      noResultsText: t('No such column found. To filter on a metric, try the Custom SQL tab.'),
-    };
-
-    if (datasource.type === 'druid') {
-      subjectSelectProps = {
-        ...subjectSelectProps,
-        placeholder: t('%s column(s) and metric(s)', options.length),
-        options,
-      };
-    } else {
-      // we cannot support simple ad-hoc filters for metrics because we don't know what type
-      // the value should be cast to (without knowing the output type of the aggregate, which
-      // becomes a rather complicated problem)
-      subjectSelectProps = {
-        ...subjectSelectProps,
-        placeholder: adhocFilter.clause === CLAUSES.WHERE ?
-          t('%s column(s)', options.length) :
-          t('To filter on a metric, use Custom SQL tab.'),
-        options: options.filter(option => option.column_name),
-      };
-    }
-
-    const operatorSelectProps = {
-      placeholder: t('%s operators(s)', Object.keys(OPERATORS).length),
-      options: Object.keys(OPERATORS).filter(this.isOperatorRelevant).map((
-        operator => ({ operator })
-      )),
-      value: adhocFilter.operator,
-      onChange: this.onOperatorChange,
-      optionRenderer: VirtualizedRendererWrap((
-        operator => translateOperator(operator.operator)
-      )),
-      valueRenderer: operator => (
-        <span>
-          {translateOperator(operator.operator)}
-        </span>
-      ),
-      valueKey: 'operator',
-    };
-
-    return (
-      <span>
-        <FormGroup className="adhoc-filter-simple-column-dropdown">
-          <OnPasteSelect {...this.selectProps} {...subjectSelectProps} />
-        </FormGroup>
-        <FormGroup>
-          <OnPasteSelect {...this.selectProps} {...operatorSelectProps} />
-        </FormGroup>
-        <FormGroup>
-          {
-            (
-              MULTI_OPERATORS.indexOf(adhocFilter.operator) >= 0 ||
-              this.state.suggestions.length > 0
-            ) ?
-              <SelectControl
-                multi={MULTI_OPERATORS.indexOf(adhocFilter.operator) >= 0}
-                freeForm
-                name="filter-comparator-value"
-                value={adhocFilter.comparator}
-                isLoading={false}
-                choices={this.state.suggestions}
-                onChange={this.onComparatorChange}
-                showHeader={false}
-                noResultsText={t('type a value here')}
-                refFunc={this.multiComparatorRef}
-              /> :
-              <input
-                ref={this.focusComparator}
-                type="text"
-                onChange={this.onInputComparatorChange}
-                value={adhocFilter.comparator || ''}
-                className="form-control input-sm"
-                placeholder={t('Filter value')}
-              />
-          }
-        </FormGroup>
-      </span>
-    );
-  }
-}
-AdhocFilterEditPopoverSimpleTabContent.propTypes = propTypes;
-AdhocFilterEditPopoverSimpleTabContent.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx b/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
deleted file mode 100644
index 7e8a6a6a39..0000000000
--- a/superset/assets/src/explore/components/AdhocFilterEditPopoverSqlTabContent.jsx
+++ /dev/null
@@ -1,133 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import AceEditor from 'react-ace';
-import 'brace/mode/sql';
-import 'brace/theme/github';
-import 'brace/ext/language_tools';
-import { FormGroup } from 'react-bootstrap';
-import VirtualizedSelect from 'react-virtualized-select';
-
-import { sqlWords } from '../../SqlLab/components/AceEditorWrapper';
-import AdhocFilter, { EXPRESSION_TYPES, CLAUSES } from '../AdhocFilter';
-import adhocMetricType from '../propTypes/adhocMetricType';
-import columnType from '../propTypes/columnType';
-import OnPasteSelect from '../../components/OnPasteSelect';
-import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
-import { t } from '../../locales';
-
-const propTypes = {
-  adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
-  onChange: PropTypes.func.isRequired,
-  options: PropTypes.arrayOf(PropTypes.oneOfType([
-    columnType,
-    PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
-    adhocMetricType,
-  ])).isRequired,
-  height: PropTypes.number.isRequired,
-};
-
-const langTools = ace.acequire('ace/ext/language_tools');
-
-export default class AdhocFilterEditPopoverSqlTabContent extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onSqlExpressionChange = this.onSqlExpressionChange.bind(this);
-    this.onSqlExpressionClauseChange = this.onSqlExpressionClauseChange.bind(this);
-    this.handleAceEditorRef = this.handleAceEditorRef.bind(this);
-
-    this.selectProps = {
-      multi: false,
-      name: 'select-column',
-      labelKey: 'label',
-      autosize: false,
-      clearable: false,
-      selectWrap: VirtualizedSelect,
-    };
-
-    if (langTools) {
-      const words = sqlWords.concat(this.props.options.map((option) => {
-        if (option.column_name) {
-          return { name: option.column_name, value: option.column_name, score: 50, meta: 'option' };
-        }
-        return null;
-      }));
-      const completer = {
-        getCompletions: (aceEditor, session, pos, prefix, callback) => {
-          callback(null, words);
-        },
-      };
-      langTools.setCompleters([completer]);
-    }
-  }
-
-  componentDidUpdate() {
-    this.aceEditorRef.editor.resize();
-  }
-
-  onSqlExpressionClauseChange(clause) {
-    this.props.onChange(this.props.adhocFilter.duplicateWith({
-      clause: clause && clause.clause,
-      expressionType: EXPRESSION_TYPES.SQL,
-    }));
-  }
-
-  onSqlExpressionChange(sqlExpression) {
-    this.props.onChange(this.props.adhocFilter.duplicateWith({
-      sqlExpression,
-      expressionType: EXPRESSION_TYPES.SQL,
-    }));
-  }
-
-  handleAceEditorRef(ref) {
-    if (ref) {
-      this.aceEditorRef = ref;
-    }
-  }
-
-  render() {
-    const { adhocFilter, height } = this.props;
-
-    const clauseSelectProps = {
-      placeholder: t('choose WHERE or HAVING...'),
-      options: Object.keys(CLAUSES).map(clause => ({ clause })),
-      value: adhocFilter.clause,
-      onChange: this.onSqlExpressionClauseChange,
-      optionRenderer: VirtualizedRendererWrap(clause => clause.clause),
-      valueRenderer: clause => <span>{clause.clause}</span>,
-      valueKey: 'clause',
-    };
-
-    return (
-      <span>
-        <FormGroup className="filter-edit-clause-section">
-          <OnPasteSelect
-            {...this.selectProps}
-            {...clauseSelectProps}
-            className="filter-edit-clause-dropdown"
-          />
-          <span className="filter-edit-clause-info">
-            <strong>Where</strong> filters by columns.<br />
-            <strong>Having</strong> filters by metrics.
-          </span>
-        </FormGroup>
-        <FormGroup>
-          <AceEditor
-            ref={this.handleAceEditorRef}
-            mode="sql"
-            theme="github"
-            height={(height - 100) + 'px'}
-            onChange={this.onSqlExpressionChange}
-            width="100%"
-            showGutter={false}
-            value={adhocFilter.sqlExpression || adhocFilter.translateToSql()}
-            editorProps={{ $blockScrolling: true }}
-            enableLiveAutocompletion
-            className="adhoc-filter-sql-editor"
-            wrapEnabled
-          />
-        </FormGroup>
-      </span>
-    );
-  }
-}
-AdhocFilterEditPopoverSqlTabContent.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AdhocFilterOption.jsx b/superset/assets/src/explore/components/AdhocFilterOption.jsx
deleted file mode 100644
index eb7a5c16d6..0000000000
--- a/superset/assets/src/explore/components/AdhocFilterOption.jsx
+++ /dev/null
@@ -1,93 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Label, OverlayTrigger } from 'react-bootstrap';
-
-import AdhocFilterEditPopover from './AdhocFilterEditPopover';
-import AdhocFilter from '../AdhocFilter';
-import columnType from '../propTypes/columnType';
-import adhocMetricType from '../propTypes/adhocMetricType';
-
-const propTypes = {
-  adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
-  onFilterEdit: PropTypes.func.isRequired,
-  options: PropTypes.arrayOf(PropTypes.oneOfType([
-    columnType,
-    PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
-    adhocMetricType,
-  ])).isRequired,
-  datasource: PropTypes.object,
-};
-
-export default class AdhocFilterOption extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.closeFilterEditOverlay = this.closeFilterEditOverlay.bind(this);
-    this.onPopoverResize = this.onPopoverResize.bind(this);
-    this.onOverlayEntered = this.onOverlayEntered.bind(this);
-    this.onOverlayExited = this.onOverlayExited.bind(this);
-    this.state = { overlayShown: !this.props.adhocFilter.fromFormData };
-  }
-
-  onPopoverResize() {
-   this.forceUpdate();
-  }
-
-  onOverlayEntered() {
-    this.setState({ overlayShown: true });
-  }
-
-  onOverlayExited() {
-    this.setState({ overlayShown: false });
-  }
-
-  onMouseDown(e) {
-    e.stopPropagation();
-  }
-
-  closeFilterEditOverlay() {
-    this.refs.overlay.hide();
-  }
-
-  render() {
-    const { adhocFilter } = this.props;
-    const overlay = (
-      <AdhocFilterEditPopover
-        onResize={this.onPopoverResize}
-        adhocFilter={adhocFilter}
-        onChange={this.props.onFilterEdit}
-        onClose={this.closeFilterEditOverlay}
-        options={this.props.options}
-        datasource={this.props.datasource}
-      />
-    );
-
-    return (
-      <OverlayTrigger
-        ref="overlay"
-        placement="right"
-        trigger="click"
-        disabled
-        overlay={overlay}
-        rootClose
-        shouldUpdatePosition
-        defaultOverlayShown={!adhocFilter.fromFormData}
-        onEntered={this.onOverlayEntered}
-        onExited={this.onOverlayExited}
-      >
-        <Label className="adhoc-filter-option">
-          <div onMouseDownCapture={this.onMouseDown}>
-            <span className="m-r-5 option-label">
-              {adhocFilter.getDefaultLabel()}
-              <i
-                className={
-                  `glyphicon glyphicon-triangle-${this.state.overlayShown ? 'left' : 'right'} adhoc-label-arrow`
-                }
-              />
-            </span>
-          </div>
-        </Label>
-      </OverlayTrigger>
-    );
-  }
-}
-AdhocFilterOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx b/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx
deleted file mode 100644
index 344e22a49c..0000000000
--- a/superset/assets/src/explore/components/AdhocMetricEditPopover.jsx
+++ /dev/null
@@ -1,271 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Button, ControlLabel, FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
-import VirtualizedSelect from 'react-virtualized-select';
-import AceEditor from 'react-ace';
-import 'brace/mode/sql';
-import 'brace/theme/github';
-import 'brace/ext/language_tools';
-
-import { AGGREGATES } from '../constants';
-import { t } from '../../locales';
-import VirtualizedRendererWrap from '../../components/VirtualizedRendererWrap';
-import OnPasteSelect from '../../components/OnPasteSelect';
-import AdhocMetricEditPopoverTitle from './AdhocMetricEditPopoverTitle';
-import columnType from '../propTypes/columnType';
-import AdhocMetric, { EXPRESSION_TYPES } from '../AdhocMetric';
-import ColumnOption from '../../components/ColumnOption';
-import { sqlWords } from '../../SqlLab/components/AceEditorWrapper';
-
-const langTools = ace.acequire('ace/ext/language_tools');
-
-const propTypes = {
-  adhocMetric: PropTypes.instanceOf(AdhocMetric).isRequired,
-  onChange: PropTypes.func.isRequired,
-  onClose: PropTypes.func.isRequired,
-  onResize: PropTypes.func.isRequired,
-  columns: PropTypes.arrayOf(columnType),
-  datasourceType: PropTypes.string,
-};
-
-const defaultProps = {
-  columns: [],
-};
-
-const startingWidth = 300;
-const startingHeight = 180;
-
-export default class AdhocMetricEditPopover extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onSave = this.onSave.bind(this);
-    this.onColumnChange = this.onColumnChange.bind(this);
-    this.onAggregateChange = this.onAggregateChange.bind(this);
-    this.onSqlExpressionChange = this.onSqlExpressionChange.bind(this);
-    this.onLabelChange = this.onLabelChange.bind(this);
-    this.onDragDown = this.onDragDown.bind(this);
-    this.onMouseMove = this.onMouseMove.bind(this);
-    this.onMouseUp = this.onMouseUp.bind(this);
-    this.handleAceEditorRef = this.handleAceEditorRef.bind(this);
-    this.refreshAceEditor = this.refreshAceEditor.bind(this);
-    this.state = {
-      adhocMetric: this.props.adhocMetric,
-      width: startingWidth,
-      height: startingHeight,
-    };
-    this.selectProps = {
-      multi: false,
-      name: 'select-column',
-      labelKey: 'label',
-      autosize: false,
-      clearable: true,
-      selectWrap: VirtualizedSelect,
-    };
-    if (langTools) {
-      const words = sqlWords.concat(this.props.columns.map(column => (
-        { name: column.column_name, value: column.column_name, score: 50, meta: 'column' }
-      )));
-      const completer = {
-        getCompletions: (aceEditor, session, pos, prefix, callback) => {
-          callback(null, words);
-        },
-      };
-      langTools.setCompleters([completer]);
-    }
-    document.addEventListener('mouseup', this.onMouseUp);
-  }
-
-  componentWillUnmount() {
-    document.removeEventListener('mouseup', this.onMouseUp);
-    document.removeEventListener('mousemove', this.onMouseMove);
-  }
-
-  onSave() {
-    this.props.onChange(this.state.adhocMetric);
-    this.props.onClose();
-  }
-
-  onColumnChange(column) {
-    this.setState({ adhocMetric: this.state.adhocMetric.duplicateWith({
-      column,
-      expressionType: EXPRESSION_TYPES.SIMPLE,
-    }) });
-  }
-
-  onAggregateChange(aggregate) {
-    // we construct this object explicitly to overwrite the value in the case aggregate is null
-    this.setState({
-      adhocMetric: this.state.adhocMetric.duplicateWith({
-        aggregate: aggregate && aggregate.aggregate,
-        expressionType: EXPRESSION_TYPES.SIMPLE,
-      }),
-    });
-  }
-
-  onSqlExpressionChange(sqlExpression) {
-    this.setState({
-      adhocMetric: this.state.adhocMetric.duplicateWith({
-        sqlExpression,
-        expressionType: EXPRESSION_TYPES.SQL,
-      }),
-    });
-  }
-
-  onLabelChange(e) {
-    this.setState({
-      adhocMetric: this.state.adhocMetric.duplicateWith({
-        label: e.target.value, hasCustomLabel: true,
-      }),
-    });
-  }
-
-  onDragDown(e) {
-    this.dragStartX = e.clientX;
-    this.dragStartY = e.clientY;
-    this.dragStartWidth = this.state.width;
-    this.dragStartHeight = this.state.height;
-    document.addEventListener('mousemove', this.onMouseMove);
-  }
-
-  onMouseMove(e) {
-    this.props.onResize();
-    this.setState({
-      width: Math.max(this.dragStartWidth + (e.clientX - this.dragStartX), startingWidth),
-      height: Math.max(this.dragStartHeight + (e.clientY - this.dragStartY) * 2, startingHeight),
-    });
-  }
-
-  onMouseUp() {
-    document.removeEventListener('mousemove', this.onMouseMove);
-  }
-
-  handleAceEditorRef(ref) {
-    if (ref) {
-      this.aceEditorRef = ref;
-    }
-  }
-
-  refreshAceEditor() {
-    setTimeout(() => this.aceEditorRef.editor.resize(), 0);
-  }
-
-  render() {
-    const {
-      adhocMetric: propsAdhocMetric,
-      columns,
-      onChange,
-      onClose,
-      onResize,
-      datasourceType,
-      ...popoverProps
-    } = this.props;
-
-    const { adhocMetric } = this.state;
-
-    const columnSelectProps = {
-      placeholder: t('%s column(s)', columns.length),
-      options: columns,
-      value: (adhocMetric.column && adhocMetric.column.column_name) ||
-        adhocMetric.inferSqlExpressionColumn(),
-      onChange: this.onColumnChange,
-      optionRenderer: VirtualizedRendererWrap(option => (
-        <ColumnOption column={option} showType />
-      )),
-      valueRenderer: column => column.column_name,
-      valueKey: 'column_name',
-    };
-
-    const aggregateSelectProps = {
-      placeholder: t('%s aggregates(s)', Object.keys(AGGREGATES).length),
-      options: Object.keys(AGGREGATES).map(aggregate => ({ aggregate })),
-      value: adhocMetric.aggregate || adhocMetric.inferSqlExpressionAggregate(),
-      onChange: this.onAggregateChange,
-      optionRenderer: VirtualizedRendererWrap(aggregate => aggregate.aggregate),
-      valueRenderer: aggregate => aggregate.aggregate,
-      valueKey: 'aggregate',
-    };
-
-    if (this.props.datasourceType === 'druid') {
-      aggregateSelectProps.options = aggregateSelectProps.options.filter((
-        option => option.aggregate !== 'AVG'
-      ));
-    }
-
-    const popoverTitle = (
-      <AdhocMetricEditPopoverTitle
-        adhocMetric={adhocMetric}
-        onChange={this.onLabelChange}
-      />
-    );
-
-    const stateIsValid = adhocMetric.isValid();
-    const hasUnsavedChanges = !adhocMetric.equals(propsAdhocMetric);
-
-    return (
-      <Popover
-        id="metrics-edit-popover"
-        title={popoverTitle}
-        {...popoverProps}
-      >
-        <Tabs
-          id="adhoc-metric-edit-tabs"
-          defaultActiveKey={adhocMetric.expressionType}
-          className="adhoc-metric-edit-tabs"
-          style={{ height: this.state.height, width: this.state.width }}
-          onSelect={this.refreshAceEditor}
-          animation={false}
-        >
-          <Tab className="adhoc-metric-edit-tab" eventKey={EXPRESSION_TYPES.SIMPLE} title="Simple">
-            <FormGroup>
-              <ControlLabel><strong>column</strong></ControlLabel>
-              <OnPasteSelect {...this.selectProps} {...columnSelectProps} />
-            </FormGroup>
-            <FormGroup>
-              <ControlLabel><strong>aggregate</strong></ControlLabel>
-              <OnPasteSelect {...this.selectProps} {...aggregateSelectProps} />
-            </FormGroup>
-          </Tab>
-          <Tab className="adhoc-metric-edit-tab" eventKey={EXPRESSION_TYPES.SQL} title="Custom SQL">
-            {
-              this.props.datasourceType !== 'druid' ?
-                <FormGroup>
-                  <AceEditor
-                    ref={this.handleAceEditorRef}
-                    mode="sql"
-                    theme="github"
-                    height={(this.state.height - 43) + 'px'}
-                    onChange={this.onSqlExpressionChange}
-                    width="100%"
-                    showGutter={false}
-                    value={adhocMetric.sqlExpression || adhocMetric.translateToSql()}
-                    editorProps={{ $blockScrolling: true }}
-                    enableLiveAutocompletion
-                    className="adhoc-filter-sql-editor"
-                    wrapEnabled
-                  />
-                </FormGroup> :
-                <div className="custom-sql-disabled-message">
-                  Custom SQL Metrics are not available on druid datasources
-                </div>
-            }
-          </Tab>
-        </Tabs>
-        <div>
-          <Button
-            disabled={!stateIsValid}
-            bsStyle={(hasUnsavedChanges && stateIsValid) ? 'primary' : 'default'}
-            bsSize="small"
-            className="m-r-5"
-            onClick={this.onSave}
-          >
-            Save
-          </Button>
-          <Button bsSize="small" onClick={this.props.onClose}>Close</Button>
-          <i onMouseDown={this.onDragDown} className="glyphicon glyphicon-resize-full edit-popover-resize" />
-        </div>
-      </Popover>
-    );
-  }
-}
-AdhocMetricEditPopover.propTypes = propTypes;
-AdhocMetricEditPopover.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/AdhocMetricEditPopoverTitle.jsx b/superset/assets/src/explore/components/AdhocMetricEditPopoverTitle.jsx
deleted file mode 100644
index d14b111189..0000000000
--- a/superset/assets/src/explore/components/AdhocMetricEditPopoverTitle.jsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FormControl, OverlayTrigger, Tooltip } from 'react-bootstrap';
-import AdhocMetric from '../AdhocMetric';
-
-const propTypes = {
-  adhocMetric: PropTypes.instanceOf(AdhocMetric),
-  onChange: PropTypes.func.isRequired,
-};
-
-export default class AdhocMetricEditPopoverTitle extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onMouseOver = this.onMouseOver.bind(this);
-    this.onMouseOut = this.onMouseOut.bind(this);
-    this.onClick = this.onClick.bind(this);
-    this.onBlur = this.onBlur.bind(this);
-    this.state = {
-      isHovered: false,
-      isEditable: false,
-    };
-  }
-
-  onMouseOver() {
-    this.setState({ isHovered: true });
-  }
-
-  onMouseOut() {
-    this.setState({ isHovered: false });
-  }
-
-  onClick() {
-    this.setState({ isEditable: true });
-  }
-
-  onBlur() {
-    this.setState({ isEditable: false });
-  }
-
-  refFunc(ref) {
-    if (ref) {
-      ref.focus();
-    }
-  }
-
-  render() {
-    const { adhocMetric, onChange } = this.props;
-
-    const editPrompt = <Tooltip id="edit-metric-label-tooltip">Click to edit label</Tooltip>;
-
-    return (
-      <OverlayTrigger
-        placement="top"
-        overlay={editPrompt}
-        onMouseOver={this.onMouseOver}
-        onMouseOut={this.onMouseOut}
-        onClick={this.onClick}
-        onBlur={this.onBlur}
-      >
-        {this.state.isEditable ?
-          <FormControl
-            className="metric-edit-popover-label-input"
-            type="text"
-            placeholder={adhocMetric.label}
-            value={adhocMetric.hasCustomLabel ? adhocMetric.label : ''}
-            onChange={onChange}
-            inputRef={this.refFunc}
-          /> :
-          <span>
-            {adhocMetric.hasCustomLabel ? adhocMetric.label : 'My Metric'}
-            &nbsp;
-            <i className="fa fa-pencil" style={{ color: this.state.isHovered ? 'black' : 'grey' }} />
-          </span>
-        }
-      </OverlayTrigger>
-    );
-  }
-}
-AdhocMetricEditPopoverTitle.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AdhocMetricOption.jsx b/superset/assets/src/explore/components/AdhocMetricOption.jsx
deleted file mode 100644
index 482557a7a7..0000000000
--- a/superset/assets/src/explore/components/AdhocMetricOption.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Label, OverlayTrigger } from 'react-bootstrap';
-
-import AdhocMetricEditPopover from './AdhocMetricEditPopover';
-import AdhocMetric from '../AdhocMetric';
-import columnType from '../propTypes/columnType';
-
-const propTypes = {
-  adhocMetric: PropTypes.instanceOf(AdhocMetric),
-  onMetricEdit: PropTypes.func.isRequired,
-  columns: PropTypes.arrayOf(columnType),
-  multi: PropTypes.bool,
-  datasourceType: PropTypes.string,
-};
-
-export default class AdhocMetricOption extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.closeMetricEditOverlay = this.closeMetricEditOverlay.bind(this);
-    this.onOverlayEntered = this.onOverlayEntered.bind(this);
-    this.onOverlayExited = this.onOverlayExited.bind(this);
-    this.onPopoverResize = this.onPopoverResize.bind(this);
-    this.state = { overlayShown: !this.props.adhocMetric.fromFormData };
-  }
-
-  onPopoverResize() {
-    this.forceUpdate();
-  }
-
-  onOverlayEntered() {
-    this.setState({ overlayShown: true });
-  }
-
-  onOverlayExited() {
-    this.setState({ overlayShown: false });
-  }
-
-  closeMetricEditOverlay() {
-    this.refs.overlay.hide();
-  }
-
-  render() {
-    const { adhocMetric } = this.props;
-    const overlay = (
-      <AdhocMetricEditPopover
-        onResize={this.onPopoverResize}
-        adhocMetric={adhocMetric}
-        onChange={this.props.onMetricEdit}
-        onClose={this.closeMetricEditOverlay}
-        columns={this.props.columns}
-        datasourceType={this.props.datasourceType}
-      />
-    );
-
-    return (
-      <OverlayTrigger
-        ref="overlay"
-        placement="right"
-        trigger="click"
-        disabled
-        overlay={overlay}
-        rootClose
-        shouldUpdatePosition
-        defaultOverlayShown={!adhocMetric.fromFormData}
-        onEntered={this.onOverlayEntered}
-        onExited={this.onOverlayExited}
-      >
-        <Label style={{ margin: this.props.multi ? 0 : 3, cursor: 'pointer' }}>
-          <div onMouseDownCapture={(e) => { e.stopPropagation(); }}>
-            <span className="m-r-5 option-label">
-              {adhocMetric.label}
-              <i
-                className={
-                  `glyphicon glyphicon-triangle-${this.state.overlayShown ? 'left' : 'right'} adhoc-label-arrow`
-                }
-              />
-            </span>
-          </div>
-        </Label>
-      </OverlayTrigger>
-    );
-  }
-}
-AdhocMetricOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AdhocMetricStaticOption.jsx b/superset/assets/src/explore/components/AdhocMetricStaticOption.jsx
deleted file mode 100644
index bce6493ec3..0000000000
--- a/superset/assets/src/explore/components/AdhocMetricStaticOption.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import ColumnTypeLabel from '../../components/ColumnTypeLabel';
-import adhocMetricType from '../propTypes/adhocMetricType';
-
-const propTypes = {
-  adhocMetric: adhocMetricType,
-  showType: PropTypes.bool,
-};
-
-export default function AdhocMetricStaticOption({ adhocMetric, showType }) {
-  return (
-    <div>
-      {showType && <ColumnTypeLabel type="expression" />}
-      <span className="m-r-5 option-label">
-        {adhocMetric.label}
-      </span>
-    </div>
-  );
-}
-AdhocMetricStaticOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/AggregateOption.jsx b/superset/assets/src/explore/components/AggregateOption.jsx
deleted file mode 100644
index e56ccf9dbf..0000000000
--- a/superset/assets/src/explore/components/AggregateOption.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import ColumnTypeLabel from '../../components/ColumnTypeLabel';
-import aggregateOptionType from '../propTypes/aggregateOptionType';
-
-const propTypes = {
-  aggregate: aggregateOptionType,
-  showType: PropTypes.bool,
-};
-
-export default function AggregateOption({ aggregate, showType }) {
-  return (
-    <div>
-      {showType && <ColumnTypeLabel type="aggregate" />}
-      <span className="m-r-5 option-label">
-        {aggregate.aggregate_name}
-      </span>
-    </div>
-  );
-}
-AggregateOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/Control.jsx b/superset/assets/src/explore/components/Control.jsx
deleted file mode 100644
index 52682dee00..0000000000
--- a/superset/assets/src/explore/components/Control.jsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import controlMap from './controls';
-
-const controlTypes = Object.keys(controlMap);
-
-const propTypes = {
-  actions: PropTypes.object.isRequired,
-  name: PropTypes.string.isRequired,
-  type: PropTypes.oneOf(controlTypes).isRequired,
-  hidden: PropTypes.bool,
-  label: PropTypes.string.isRequired,
-  choices: PropTypes.arrayOf(PropTypes.array),
-  description: PropTypes.string,
-  tooltipOnClick: PropTypes.func,
-  places: PropTypes.number,
-  validators: PropTypes.array,
-  validationErrors: PropTypes.array,
-  renderTrigger: PropTypes.bool,
-  rightNode: PropTypes.node,
-  formData: PropTypes.object,
-  value: PropTypes.oneOfType([
-    PropTypes.string,
-    PropTypes.number,
-    PropTypes.object,
-    PropTypes.bool,
-    PropTypes.array,
-    PropTypes.func]),
-};
-
-const defaultProps = {
-  renderTrigger: false,
-  validators: [],
-  hidden: false,
-  validationErrors: [],
-};
-
-export default class Control extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = { hovered: false };
-    this.validate = this.validate.bind(this);
-    this.onChange = this.onChange.bind(this);
-  }
-  componentDidMount() {
-    this.validateAndSetValue(this.props.value, []);
-  }
-  onChange(value, errors) {
-    this.validateAndSetValue(value, errors);
-  }
-  setHover(hovered) {
-    this.setState({ hovered });
-  }
-  validateAndSetValue(value, errors) {
-    let validationErrors = this.props.validationErrors;
-    let currentErrors = this.validate(value);
-    if (errors && errors.length > 0) {
-      currentErrors = validationErrors.concat(errors);
-    }
-    if (validationErrors.length + currentErrors.length > 0) {
-      validationErrors = currentErrors;
-    }
-
-    if (value !== this.props.value || validationErrors !== this.props.validationErrors) {
-      this.props.actions.setControlValue(this.props.name, value, validationErrors);
-    }
-  }
-  validate(value) {
-    const validators = this.props.validators;
-    const validationErrors = [];
-    if (validators && validators.length > 0) {
-      validators.forEach((f) => {
-        const v = f(value);
-        if (v) {
-          validationErrors.push(v);
-        }
-      });
-    }
-    return validationErrors;
-  }
-  render() {
-    const ControlType = controlMap[this.props.type];
-    const divStyle = this.props.hidden ? { display: 'none' } : null;
-    return (
-      <div
-        style={divStyle}
-        onMouseEnter={this.setHover.bind(this, true)}
-        onMouseLeave={this.setHover.bind(this, false)}
-      >
-        <ControlType
-          onChange={this.onChange}
-          hovered={this.state.hovered}
-          {...this.props}
-        />
-      </div>
-    );
-  }
-}
-
-Control.propTypes = propTypes;
-Control.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/ControlHeader.jsx b/superset/assets/src/explore/components/ControlHeader.jsx
deleted file mode 100644
index 3dd884ce21..0000000000
--- a/superset/assets/src/explore/components/ControlHeader.jsx
+++ /dev/null
@@ -1,136 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { ControlLabel, OverlayTrigger, Tooltip } from 'react-bootstrap';
-import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger';
-import { t } from '../../locales';
-
-const propTypes = {
-  label: PropTypes.string,
-  description: PropTypes.string,
-  validationErrors: PropTypes.array,
-  renderTrigger: PropTypes.bool,
-  rightNode: PropTypes.node,
-  leftNode: PropTypes.node,
-  onClick: PropTypes.func,
-  hovered: PropTypes.bool,
-  tooltipOnClick: PropTypes.func,
-  warning: PropTypes.string,
-  danger: PropTypes.string,
-};
-
-const defaultProps = {
-  validationErrors: [],
-  renderTrigger: false,
-  hovered: false,
-};
-
-export default class ControlHeader extends React.Component {
-  renderOptionalIcons() {
-    if (this.props.hovered) {
-      return (
-        <span>
-          {this.props.description &&
-            <span>
-              <InfoTooltipWithTrigger
-                label={t('description')}
-                tooltip={this.props.description}
-                placement="top"
-                onClick={this.props.tooltipOnClick}
-              />
-              {' '}
-            </span>
-          }
-          {this.props.renderTrigger &&
-            <span>
-              <InfoTooltipWithTrigger
-                label={t('bolt')}
-                tooltip={t('Changing this control takes effect instantly')}
-                placement="top"
-                icon="bolt"
-              />
-              {' '}
-            </span>
-          }
-        </span>);
-    }
-    return null;
-  }
-  render() {
-    if (!this.props.label) {
-      return null;
-    }
-    const labelClass = (this.props.validationErrors.length > 0) ? 'text-danger' : '';
-    return (
-      <div
-        className="ControlHeader"
-      >
-        <div className="pull-left">
-          <ControlLabel>
-            {this.props.leftNode &&
-              <span>{this.props.leftNode}</span>
-            }
-            <span
-              onClick={this.props.onClick}
-              className={labelClass}
-              style={{ cursor: this.props.onClick ? 'pointer' : '' }}
-            >
-              {this.props.label}
-            </span>
-            {' '}
-            {(this.props.warning) &&
-              <span>
-                <OverlayTrigger
-                  placement="top"
-                  overlay={
-                    <Tooltip id={'error-tooltip'}>{this.props.warning}</Tooltip>
-                  }
-                >
-                  <i className="fa fa-exclamation-circle text-warning" />
-                </OverlayTrigger>
-                {' '}
-              </span>
-            }
-            {(this.props.danger) &&
-              <span>
-                <OverlayTrigger
-                  placement="top"
-                  overlay={
-                    <Tooltip id={'error-tooltip'}>{this.props.danger}</Tooltip>
-                  }
-                >
-                  <i className="fa fa-exclamation-circle text-danger" />
-                </OverlayTrigger>
-                {' '}
-              </span>
-            }
-            {(this.props.validationErrors.length > 0) &&
-              <span>
-                <OverlayTrigger
-                  placement="top"
-                  overlay={
-                    <Tooltip id={'error-tooltip'}>
-                      {this.props.validationErrors.join(' ')}
-                    </Tooltip>
-                  }
-                >
-                  <i className="fa fa-exclamation-circle text-danger" />
-                </OverlayTrigger>
-                {' '}
-              </span>
-            }
-            {this.renderOptionalIcons()}
-          </ControlLabel>
-        </div>
-        {this.props.rightNode &&
-          <div className="pull-right">
-            {this.props.rightNode}
-          </div>
-        }
-        <div className="clearfix" />
-      </div>
-    );
-  }
-}
-
-ControlHeader.propTypes = propTypes;
-ControlHeader.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/ControlPanelsContainer.jsx b/superset/assets/src/explore/components/ControlPanelsContainer.jsx
index 1bf653f938..85f61a26d7 100644
--- a/superset/assets/src/explore/components/ControlPanelsContainer.jsx
+++ b/superset/assets/src/explore/components/ControlPanelsContainer.jsx
@@ -7,7 +7,7 @@ import { Alert, Tab, Tabs } from 'react-bootstrap';
 import visTypes, { sectionsToRender } from '../visTypes';
 import ControlPanelSection from './ControlPanelSection';
 import ControlRow from './ControlRow';
-import Control from './Control';
+import Control from '../../controls/Control';
 import controls from '../controls';
 import * as actions from '../actions/exploreActions';
 
diff --git a/superset/assets/src/explore/components/FilterDefinitionOption.jsx b/superset/assets/src/explore/components/FilterDefinitionOption.jsx
deleted file mode 100644
index 34355f75d5..0000000000
--- a/superset/assets/src/explore/components/FilterDefinitionOption.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import ColumnOption from '../../components/ColumnOption';
-import ColumnTypeLabel from '../../components/ColumnTypeLabel';
-import AdhocMetricStaticOption from './AdhocMetricStaticOption';
-import columnType from '../propTypes/columnType';
-import adhocMetricType from '../propTypes/adhocMetricType';
-
-const propTypes = {
-  option: PropTypes.oneOfType([
-    columnType,
-    PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
-    adhocMetricType,
-  ]).isRequired,
-};
-
-export default function FilterDefinitionOption({ option }) {
-  if (option.saved_metric_name) {
-    return (
-      <div>
-        <ColumnTypeLabel type="expression" />
-        <span className="m-r-5 option-label">
-          {option.saved_metric_name}
-        </span>
-      </div>
-    );
-  } else if (option.column_name) {
-    return (
-      <ColumnOption column={option} showType />
-    );
-  } else if (option.label) {
-    return (
-      <AdhocMetricStaticOption adhocMetric={option} showType />
-    );
-  }
-}
-FilterDefinitionOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/MetricDefinitionOption.jsx b/superset/assets/src/explore/components/MetricDefinitionOption.jsx
deleted file mode 100644
index c275b9c4d5..0000000000
--- a/superset/assets/src/explore/components/MetricDefinitionOption.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import MetricOption from '../../components/MetricOption';
-import ColumnOption from '../../components/ColumnOption';
-import AggregateOption from './AggregateOption';
-import columnType from '../propTypes/columnType';
-import savedMetricType from '../propTypes/savedMetricType';
-import aggregateOptionType from '../propTypes/aggregateOptionType';
-
-const propTypes = {
-  option: PropTypes.oneOfType([
-    columnType,
-    savedMetricType,
-    aggregateOptionType,
-  ]).isRequired,
-};
-
-export default function MetricDefinitionOption({ option }) {
-  if (option.metric_name) {
-    return (
-      <MetricOption metric={option} showType />
-    );
-  } else if (option.column_name) {
-    return (
-      <ColumnOption column={option} showType />
-    );
-  } else if (option.aggregate_name) {
-    return (
-      <AggregateOption aggregate={option} showType />
-    );
-  }
-  notify.error('You must supply either a saved metric, column or aggregate to MetricDefinitionOption');
-  return null;
-}
-MetricDefinitionOption.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/MetricDefinitionValue.jsx b/superset/assets/src/explore/components/MetricDefinitionValue.jsx
deleted file mode 100644
index 5b57a7ba87..0000000000
--- a/superset/assets/src/explore/components/MetricDefinitionValue.jsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import AdhocMetricOption from './AdhocMetricOption';
-import AdhocMetric from '../AdhocMetric';
-import columnType from '../propTypes/columnType';
-import MetricOption from '../../components/MetricOption';
-import savedMetricType from '../propTypes/savedMetricType';
-import adhocMetricType from '../propTypes/adhocMetricType';
-
-const propTypes = {
-  option: PropTypes.oneOfType([
-    savedMetricType,
-    adhocMetricType,
-  ]).isRequired,
-  onMetricEdit: PropTypes.func,
-  columns: PropTypes.arrayOf(columnType),
-  multi: PropTypes.bool,
-  datasourceType: PropTypes.string,
-};
-
-export default function MetricDefinitionValue({
-  option,
-  onMetricEdit,
-  columns,
-  multi,
-  datasourceType,
-}) {
-  if (option.metric_name) {
-    return (
-      <MetricOption metric={option} />
-    );
-  } else if (option instanceof AdhocMetric) {
-    return (
-      <AdhocMetricOption
-        adhocMetric={option}
-        onMetricEdit={onMetricEdit}
-        columns={columns}
-        multi={multi}
-        datasourceType={datasourceType}
-      />
-    );
-  }
-  return null;
-}
-MetricDefinitionValue.propTypes = propTypes;
diff --git a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx b/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx
deleted file mode 100644
index b51704d4b6..0000000000
--- a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import VirtualizedSelect from 'react-virtualized-select';
-
-import { t } from '../../../locales';
-import ControlHeader from '../ControlHeader';
-import adhocFilterType from '../../propTypes/adhocFilterType';
-import adhocMetricType from '../../propTypes/adhocMetricType';
-import savedMetricType from '../../propTypes/savedMetricType';
-import columnType from '../../propTypes/columnType';
-import AdhocFilter, { CLAUSES, EXPRESSION_TYPES } from '../../AdhocFilter';
-import AdhocMetric from '../../AdhocMetric';
-import { OPERATORS } from '../../constants';
-import VirtualizedRendererWrap from '../../../components/VirtualizedRendererWrap';
-import OnPasteSelect from '../../../components/OnPasteSelect';
-import AdhocFilterOption from '../AdhocFilterOption';
-import FilterDefinitionOption from '../FilterDefinitionOption';
-
-const propTypes = {
-  name: PropTypes.string,
-  onChange: PropTypes.func,
-  value: PropTypes.arrayOf(adhocFilterType),
-  datasource: PropTypes.object,
-  columns: PropTypes.arrayOf(columnType),
-  savedMetrics: PropTypes.arrayOf(savedMetricType),
-  formData: PropTypes.shape({
-    metric: PropTypes.oneOfType([PropTypes.string, adhocMetricType]),
-    metrics: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, adhocMetricType])),
-  }),
-};
-
-const defaultProps = {
-  name: '',
-  onChange: () => {},
-  columns: [],
-  savedMetrics: [],
-  formData: {},
-};
-
-function isDictionaryForAdhocFilter(value) {
-  return value && !(value instanceof AdhocFilter) && value.expressionType;
-}
-
-export default class AdhocFilterControl extends React.Component {
-
-  constructor(props) {
-    super(props);
-    this.optionsForSelect = this.optionsForSelect.bind(this);
-    this.onFilterEdit = this.onFilterEdit.bind(this);
-    this.onChange = this.onChange.bind(this);
-    this.getMetricExpression = this.getMetricExpression.bind(this);
-
-    const filters = (this.props.value || []).map(filter => (
-      isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter
-    ));
-
-    this.optionRenderer = VirtualizedRendererWrap(option => (
-      <FilterDefinitionOption option={option} />
-    ));
-    this.valueRenderer = adhocFilter => (
-      <AdhocFilterOption
-        adhocFilter={adhocFilter}
-        onFilterEdit={this.onFilterEdit}
-        options={this.state.options}
-        datasource={this.props.datasource}
-      />
-    );
-    this.state = {
-      values: filters,
-      options: this.optionsForSelect(this.props),
-    };
-  }
-
-  componentWillReceiveProps(nextProps) {
-    if (
-      this.props.columns !== nextProps.columns ||
-      this.props.formData !== nextProps.formData
-    ) {
-      this.setState({ options: this.optionsForSelect(nextProps) });
-    }
-    if (this.props.value !== nextProps.value) {
-      this.setState({
-        values: (nextProps.value || []).map(
-          filter => (isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter
-        )),
-      });
-    }
-  }
-
-  onFilterEdit(changedFilter) {
-    this.props.onChange(this.state.values.map((value) => {
-      if (value.filterOptionName === changedFilter.filterOptionName) {
-        return changedFilter;
-      }
-      return value;
-    }));
-  }
-
-  onChange(opts) {
-    this.props.onChange(opts.map((option) => {
-      if (option.saved_metric_name) {
-        return new AdhocFilter({
-          expressionType: this.props.datasource.type === 'druid' ?
-            EXPRESSION_TYPES.SIMPLE :
-            EXPRESSION_TYPES.SQL,
-          subject: this.props.datasource.type === 'druid' ?
-            option.saved_metric_name :
-            this.getMetricExpression(option.saved_metric_name),
-          operator: OPERATORS['>'],
-          comparator: 0,
-          clause: CLAUSES.HAVING,
-        });
-      } else if (option.label) {
-        return new AdhocFilter({
-          expressionType: this.props.datasource.type === 'druid' ?
-            EXPRESSION_TYPES.SIMPLE :
-            EXPRESSION_TYPES.SQL,
-          subject: this.props.datasource.type === 'druid' ?
-            option.label :
-            new AdhocMetric(option).translateToSql(),
-          operator: OPERATORS['>'],
-          comparator: 0,
-          clause: CLAUSES.HAVING,
-        });
-      } else if (option.column_name) {
-        return new AdhocFilter({
-          expressionType: EXPRESSION_TYPES.SIMPLE,
-          subject: option.column_name,
-          operator: OPERATORS['=='],
-          comparator: '',
-          clause: CLAUSES.WHERE,
-        });
-      } else if (option instanceof AdhocFilter) {
-        return option;
-      }
-      return null;
-    }).filter(option => option));
-  }
-
-  getMetricExpression(savedMetricName) {
-    return this.props.savedMetrics.find((
-      savedMetric => savedMetric.metric_name === savedMetricName
-    )).expression;
-  }
-
-  optionsForSelect(props) {
-    const options = [
-      ...props.columns,
-      ...[...(props.formData.metrics || []), props.formData.metric].map(metric => (
-        metric && (
-          typeof metric === 'string' ?
-          { saved_metric_name: metric } :
-          new AdhocMetric(metric)
-        )
-      )),
-    ].filter(option => option);
-
-    return options.reduce((results, option) => {
-      if (option.saved_metric_name) {
-        results.push({ ...option, filterOptionName: option.saved_metric_name });
-      } else if (option.column_name) {
-        results.push({ ...option, filterOptionName: '_col_' + option.column_name });
-      } else if (option instanceof AdhocMetric) {
-        results.push({ ...option, filterOptionName: '_adhocmetric_' + option.label });
-      }
-      return results;
-    }, []).sort((a, b) => (
-      (a.saved_metric_name || a.column_name || a.label).localeCompare((
-        b.saved_metric_name || b.column_name || b.label
-      ))
-    ));
-  }
-
-  render() {
-    return (
-      <div className="metrics-select">
-        <ControlHeader {...this.props} />
-        <OnPasteSelect
-          multi
-          name={`select-${this.props.name}`}
-          placeholder={t('choose a column or metric')}
-          options={this.state.options}
-          value={this.state.values}
-          labelKey="label"
-          valueKey="filterOptionName"
-          clearable
-          closeOnSelect
-          onChange={this.onChange}
-          optionRenderer={this.optionRenderer}
-          valueRenderer={this.valueRenderer}
-          selectWrap={VirtualizedSelect}
-        />
-      </div>
-    );
-  }
-}
-
-AdhocFilterControl.propTypes = propTypes;
-AdhocFilterControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx b/superset/assets/src/explore/components/controls/AnnotationLayer.jsx
deleted file mode 100644
index 875b95922a..0000000000
--- a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx
+++ /dev/null
@@ -1,632 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { CompactPicker } from 'react-color';
-import { Button } from 'react-bootstrap';
-
-import $ from 'jquery';
-import mathjs from 'mathjs';
-
-import SelectControl from './SelectControl';
-import TextControl from './TextControl';
-import CheckboxControl from './CheckboxControl';
-
-import AnnotationTypes, {
-  DEFAULT_ANNOTATION_TYPE,
-  ANNOTATION_SOURCE_TYPES,
-  getAnnotationSourceTypeLabels,
-  getAnnotationTypeLabel,
-  getSupportedSourceTypes,
-  getSupportedAnnotationTypes,
-  requiresQuery,
-} from '../../../modules/AnnotationTypes';
-
-import { ALL_COLOR_SCHEMES } from '../../../modules/colors';
-import PopoverSection from '../../../components/PopoverSection';
-import ControlHeader from '../ControlHeader';
-import { nonEmpty } from '../../validators';
-import vizTypes from '../../visTypes';
-
-const AUTOMATIC_COLOR = '';
-
-const propTypes = {
-  name: PropTypes.string,
-  annotationType: PropTypes.string,
-  sourceType: PropTypes.string,
-  color: PropTypes.string,
-  opacity: PropTypes.string,
-  style: PropTypes.string,
-  width: PropTypes.number,
-  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-  overrides: PropTypes.object,
-  show: PropTypes.bool,
-  titleColumn: PropTypes.string,
-  descriptionColumns: PropTypes.arrayOf(PropTypes.string),
-  timeColumn: PropTypes.string,
-  intervalEndColumn: PropTypes.string,
-  vizType: PropTypes.string,
-
-  error: PropTypes.string,
-  colorScheme: PropTypes.string,
-
-  addAnnotationLayer: PropTypes.func,
-  removeAnnotationLayer: PropTypes.func,
-  close: PropTypes.func,
-};
-
-const defaultProps = {
-  name: '',
-  annotationType: DEFAULT_ANNOTATION_TYPE,
-  sourceType: '',
-  color: AUTOMATIC_COLOR,
-  opacity: '',
-  style: 'solid',
-  width: 1,
-  overrides: {},
-  colorScheme: 'd3Category10',
-  show: true,
-  titleColumn: '',
-  descriptionColumns: [],
-  timeColumn: '',
-  intervalEndColumn: '',
-
-  addAnnotationLayer: () => {},
-  removeAnnotationLayer: () => {},
-  close: () => {},
-};
-
-export default class AnnotationLayer extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    const { name, annotationType, sourceType,
-      color, opacity, style, width, value,
-      overrides, show, titleColumn, descriptionColumns,
-      timeColumn, intervalEndColumn } = props;
-    this.state = {
-      // base
-      name,
-      oldName: !this.props.name ? null : name,
-      annotationType,
-      sourceType,
-      value,
-      overrides,
-      show,
-      // slice
-      titleColumn,
-      descriptionColumns,
-      timeColumn,
-      intervalEndColumn,
-      // display
-      color: color || AUTOMATIC_COLOR,
-      opacity,
-      style,
-      width,
-      // refData
-      isNew: !this.props.name,
-      isLoadingOptions: true,
-      valueOptions: [],
-      validationErrors: {},
-    };
-    this.submitAnnotation = this.submitAnnotation.bind(this);
-    this.deleteAnnotation = this.deleteAnnotation.bind(this);
-    this.applyAnnotation = this.applyAnnotation.bind(this);
-    this.fetchOptions = this.fetchOptions.bind(this);
-    this.handleAnnotationType = this.handleAnnotationType.bind(this);
-    this.handleAnnotationSourceType =
-        this.handleAnnotationSourceType.bind(this);
-    this.handleValue = this.handleValue.bind(this);
-    this.isValidForm = this.isValidForm.bind(this);
-  }
-
-  componentDidMount() {
-    const { annotationType, sourceType, isLoadingOptions } = this.state;
-    this.fetchOptions(annotationType, sourceType, isLoadingOptions);
-  }
-
-  componentDidUpdate(prevProps, prevState) {
-    if (prevState.sourceType !== this.state.sourceType) {
-      this.fetchOptions(this.state.annotationType, this.state.sourceType, true);
-    }
-  }
-
-  isValidFormula(value, annotationType) {
-    if (annotationType === AnnotationTypes.FORMULA) {
-      try {
-        mathjs.parse(value).compile().eval({ x: 0 });
-      } catch (err) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  isValidForm() {
-    const {
-      name, annotationType, sourceType,
-      value, timeColumn, intervalEndColumn,
-    } = this.state;
-    const errors = [nonEmpty(name), nonEmpty(annotationType), nonEmpty(value)];
-    if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE) {
-      if (annotationType === AnnotationTypes.EVENT) {
-        errors.push(nonEmpty(timeColumn));
-      }
-      if (annotationType === AnnotationTypes.INTERVAL) {
-        errors.push(nonEmpty(timeColumn));
-        errors.push(nonEmpty(intervalEndColumn));
-      }
-    }
-    errors.push(this.isValidFormula(value, annotationType));
-    return !errors.filter(x => x).length;
-  }
-
-
-  handleAnnotationType(annotationType) {
-    this.setState({
-      annotationType,
-      sourceType: null,
-      validationErrors: {},
-      value: null,
-    });
-  }
-
-  handleAnnotationSourceType(sourceType) {
-    this.setState({
-      sourceType,
-      isLoadingOptions: true,
-      validationErrors: {},
-      value: null,
-    });
-  }
-
-  handleValue(value) {
-    this.setState({
-      value,
-      descriptionColumns: null,
-      intervalEndColumn: null,
-      timeColumn: null,
-      titleColumn: null,
-      overrides: { since: null, until: null },
-    });
-  }
-
-  fetchOptions(annotationType, sourceType, isLoadingOptions) {
-    if (isLoadingOptions === true) {
-      if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
-        $.ajax({
-          type: 'GET',
-          url: '/annotationlayermodelview/api/read?',
-        }).then((data) => {
-          const layers = data ? data.result.map(layer => ({
-            value: layer.id,
-            label: layer.name,
-          })) : [];
-          this.setState({
-            isLoadingOptions: false,
-            valueOptions: layers,
-          });
-        });
-      } else if (requiresQuery(sourceType)) {
-        $.ajax({
-          type: 'GET',
-          url: '/superset/user_slices',
-        }).then(data =>
-          this.setState({
-            isLoadingOptions: false,
-            valueOptions: data.filter(
-                x => getSupportedSourceTypes(annotationType)
-                .find(v => v === x.viz_type))
-                .map(x => ({ value: x.id, label: x.title, slice: x }),
-              ),
-          }),
-        );
-      } else {
-        this.setState({
-          isLoadingOptions: false,
-          valueOptions: [],
-        });
-      }
-    }
-  }
-
-  deleteAnnotation() {
-    this.props.close();
-    if (!this.state.isNew) {
-      this.props.removeAnnotationLayer(this.state);
-    }
-  }
-
-  applyAnnotation() {
-    if (this.state.name.length) {
-      const annotation = {};
-      Object.keys(this.state).forEach((k) => {
-        if (this.state[k] !== null) {
-          annotation[k] = this.state[k];
-        }
-      });
-      delete annotation.isNew;
-      delete annotation.valueOptions;
-      delete annotation.isLoadingOptions;
-      delete annotation.validationErrors;
-      annotation.color = annotation.color === AUTOMATIC_COLOR ? null : annotation.color;
-      this.props.addAnnotationLayer(annotation);
-      this.setState({ isNew: false, oldName: this.state.name });
-    }
-  }
-
-  submitAnnotation() {
-    this.applyAnnotation();
-    this.props.close();
-  }
-
-  renderValueConfiguration() {
-    const { annotationType, sourceType, value,
-      valueOptions, isLoadingOptions } = this.state;
-    let label = '';
-    let description = '';
-    if (requiresQuery(sourceType)) {
-      if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
-        label = 'Annotation Layer';
-        description = 'Select the Annotation Layer you would like to use.';
-      } else {
-        label = 'Slice';
-        description = `Use a pre defined Superset Slice as a source for annotations and overlays. 
-        'your chart must be one of these visualization types:
-        '[${getSupportedSourceTypes(annotationType)
-            .map(x => vizTypes[x].label).join(', ')}]'`;
-      }
-    } else if (annotationType === AnnotationTypes.FORMULA) {
-      label = 'Formula';
-      description = `Expects a formula with depending time parameter 'x'
-        in milliseconds since epoch. mathjs is used to evaluate the formulas.
-        Example: '2x+5'`;
-    }
-    if (requiresQuery(sourceType)) {
-      return (
-        <SelectControl
-          name="annotation-layer-value"
-          showHeader
-          hovered
-          description={description}
-          label={label}
-          placeholder=""
-          options={valueOptions}
-          isLoading={isLoadingOptions}
-          value={value}
-          onChange={this.handleValue}
-          validationErrors={!value ? ['Mandatory'] : []}
-        />
-      );
-    } if (annotationType === AnnotationTypes.FORMULA) {
-      return (
-        <TextControl
-          name="annotation-layer-value"
-          hovered
-          showHeader
-          description={description}
-          label={label}
-          placeholder=""
-          value={value}
-          onChange={this.handleValue}
-          validationErrors={this.isValidFormula(value, annotationType) ? ['Bad formula.'] : []}
-        />
-      );
-    }
-    return '';
-  }
-
-  renderSliceConfiguration() {
-    const { annotationType, sourceType, value, valueOptions, overrides, titleColumn,
-      timeColumn, intervalEndColumn, descriptionColumns } = this.state;
-    const slice = (valueOptions.find(x => x.value === value) || {}).slice;
-    if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE && slice) {
-      const columns = (slice.data.groupby || []).concat(
-        (slice.data.all_columns || [])).map(x => ({ value: x, label: x }));
-      const timeColumnOptions = slice.data.include_time ?
-        [{ value: '__timestamp', label: '__timestamp' }].concat(columns) : columns;
-      return (
-        <div style={{ marginRight: '2rem' }}>
-          <PopoverSection
-            isSelected
-            onSelect={() => {
-            }}
-            title="Annotation Slice Configuration"
-            info={
-              `This section allows you to configure how to use the slice
-               to generate annotations.`
-            }
-          >
-            {
-              (
-                annotationType === AnnotationTypes.EVENT ||
-                annotationType === AnnotationTypes.INTERVAL
-              ) &&
-              <SelectControl
-                hovered
-                name="annotation-layer-time-column"
-                label={
-                  annotationType === AnnotationTypes.INTERVAL ?
-                    'Interval Start column' : 'Event Time Column'
-                }
-                description={'This column must contain date/time information.'}
-                validationErrors={!timeColumn ? ['Mandatory'] : []}
-                clearable={false}
-                options={timeColumnOptions}
-                value={timeColumn}
-                onChange={v => this.setState({ timeColumn: v })}
-              />
-            }
-            {
-              annotationType === AnnotationTypes.INTERVAL &&
-              <SelectControl
-                hovered
-                name="annotation-layer-intervalEnd"
-                label="Interval End column"
-                description={'This column must contain date/time information.'}
-                validationErrors={!intervalEndColumn ? ['Mandatory'] : []}
-                options={columns}
-                value={intervalEndColumn}
-                onChange={v => this.setState({ intervalEndColumn: v })}
-              />
-            }
-            <SelectControl
-              hovered
-              name="annotation-layer-title"
-              label="Title Column"
-              description={'Pick a title for you annotation.'}
-              options={
-                [{ value: '', label: 'None' }].concat(columns)
-              }
-              value={titleColumn}
-              onChange={v => this.setState({ titleColumn: v })}
-            />
-            {
-              annotationType !== AnnotationTypes.TIME_SERIES &&
-              <SelectControl
-                hovered
-                name="annotation-layer-title"
-                label="Description Columns"
-                description={`Pick one or more columns that should be shown in the
-                  annotation. If you don't select a column all of them will be shown.`}
-                multi
-                options={
-                  columns
-                }
-                value={descriptionColumns}
-                onChange={v => this.setState({ descriptionColumns: v })}
-              />
-            }
-            <div style={{ marginTop: '1rem' }}>
-              <CheckboxControl
-                hovered
-                name="annotation-override-since"
-                label="Override 'Since'"
-                description={`This controls whether the "Since" field from the current
-                  view should be passed down to the chart containing the annotation data.`}
-                value={!!Object.keys(overrides).find(x => x === 'since')}
-                onChange={(v) => {
-                  delete overrides.since;
-                  if (v) {
-                    this.setState({ overrides: { ...overrides, since: null } });
-                  } else {
-                    this.setState({ overrides: { ...overrides } });
-                  }
-                }}
-              />
-              <CheckboxControl
-                hovered
-                name="annotation-override-until"
-                label="Override 'Until'"
-                description={`This controls whether the "Until" field from the current
-                  view should be passed down to the chart containing the annotation data.`}
-                value={!!Object.keys(overrides).find(x => x === 'until')}
-                onChange={(v) => {
-                  delete overrides.until;
-                  if (v) {
-                    this.setState({ overrides: { ...overrides, until: null } });
-                  } else {
-                    this.setState({ overrides: { ...overrides } });
-                  }
-                }}
-              />
-              <CheckboxControl
-                hovered
-                name="annotation-override-timegrain"
-                label="Override time grain"
-                description={`This controls whether the time grain field from the current
-                  view should be passed down to the chart containing the annotation data.`}
-                value={!!Object.keys(overrides).find(x => x === 'time_grain_sqla')}
-                onChange={(v) => {
-                  delete overrides.time_grain_sqla;
-                  delete overrides.granularity;
-                  if (v) {
-                    this.setState({
-                      overrides: {
-                        ...overrides,
-                        time_grain_sqla: null,
-                        granularity: null,
-                      },
-                    });
-                  } else {
-                    this.setState({ overrides: { ...overrides } });
-                  }
-                }}
-              />
-              <TextControl
-                hovered
-                name="annotation-layer-timeshift"
-                label="Time Shift"
-                description={`Time delta in natural language
-                  (example:  24 hours, 7 days, 56 weeks, 365 days)`}
-                placeholder=""
-                value={overrides.time_shift}
-                onChange={v => this.setState({ overrides: { ...overrides, time_shift: v } })}
-              />
-            </div>
-          </PopoverSection>
-        </div>
-      );
-    }
-    return ('');
-  }
-
-  renderDisplayConfiguration() {
-    const { color, opacity, style, width } = this.state;
-    const colorScheme = [...ALL_COLOR_SCHEMES[this.props.colorScheme]];
-    if (color && color !== AUTOMATIC_COLOR &&
-      !colorScheme.find(x => x.toLowerCase() === color.toLowerCase())) {
-      colorScheme.push(color);
-    }
-    return (
-      <PopoverSection
-        isSelected
-        onSelect={() => {}}
-        title="Display configuration"
-        info="Configure your how you overlay is displayed here."
-      >
-        <SelectControl
-          name="annotation-layer-stroke"
-          label="Style"
-            // see '../../../visualizations/nvd3_vis.css'
-          options={[
-              { value: 'solid', label: 'Solid' },
-              { value: 'dashed', label: 'Dashed' },
-              { value: 'longDashed', label: 'Long Dashed' },
-              { value: 'dotted', label: 'Dotted' },
-          ]}
-          value={style}
-          onChange={v => this.setState({ style: v })}
-        />
-        <SelectControl
-          name="annotation-layer-opacity"
-          label="Opacity"
-            // see '../../../visualizations/nvd3_vis.css'
-          options={[
-              { value: '', label: 'Solid' },
-              { value: 'opacityLow', label: '0.2' },
-              { value: 'opacityMedium', label: '0.5' },
-              { value: 'opacityHigh', label: '0.8' },
-          ]}
-          value={opacity}
-          onChange={v => this.setState({ opacity: v })}
-        />
-        <div>
-          <ControlHeader label="Color" />
-          <div style={{ display: 'flex', flexDirection: 'column' }}>
-            <CompactPicker
-              color={color}
-              colors={colorScheme}
-              onChangeComplete={v => this.setState({ color: v.hex })}
-            />
-            <Button
-              style={{ marginTop: '0.5rem', marginBottom: '0.5rem' }}
-              bsStyle={color === AUTOMATIC_COLOR ? 'success' : 'default'}
-              bsSize="xsmall"
-              onClick={() => this.setState({ color: AUTOMATIC_COLOR })}
-            >
-              Automatic Color
-            </Button>
-          </div>
-        </div>
-        <TextControl
-          name="annotation-layer-stroke-width"
-          label="Line Width"
-          isInt
-          value={width}
-          onChange={v => this.setState({ width: v })}
-        />
-      </PopoverSection>
-    );
-  }
-
-  render() {
-    const { isNew, name, annotationType,
-      sourceType, show } = this.state;
-    const isValid = this.isValidForm();
-    return (
-      <div>
-        {
-          this.props.error &&
-          <span style={{ color: 'red' }}>
-            ERROR: {this.props.error}
-          </span>
-        }
-        <div style={{ display: 'flex', flexDirection: 'row' }}>
-          <div style={{ marginRight: '2rem' }}>
-            <PopoverSection
-              isSelected
-              onSelect={() => {}}
-              title="Layer Configuration"
-              info="Configure the basics of your Annotation Layer."
-            >
-              <TextControl
-                name="annotation-layer-name"
-                label="Name"
-                placeholder=""
-                value={name}
-                onChange={v => this.setState({ name: v })}
-                validationErrors={!name ? ['Mandatory'] : []}
-              />
-              <CheckboxControl
-                name="annotation-layer-hide"
-                label="Hide Layer"
-                value={!show}
-                onChange={v => this.setState({ show: !v })}
-              />
-              <SelectControl
-                hovered
-                description="Choose the Annotation Layer Type"
-                label="Annotation Layer Type"
-                name="annotation-layer-type"
-                options={getSupportedAnnotationTypes(this.props.vizType).map(
-                    x => ({ value: x, label: getAnnotationTypeLabel(x) }))}
-                value={annotationType}
-                onChange={this.handleAnnotationType}
-              />
-              {!!getSupportedSourceTypes(annotationType).length &&
-                <SelectControl
-                  hovered
-                  description="Choose the source of your annotations"
-                  label="Annotation Source"
-                  name="annotation-source-type"
-                  options={getSupportedSourceTypes(annotationType).map(
-                        x => ({ value: x, label: getAnnotationSourceTypeLabels(x) }))}
-                  value={sourceType}
-                  onChange={this.handleAnnotationSourceType}
-                />
-              }
-              { this.renderValueConfiguration() }
-            </PopoverSection>
-          </div>
-          { this.renderSliceConfiguration() }
-          { this.renderDisplayConfiguration() }
-        </div>
-        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
-          <Button
-            bsSize="sm"
-            onClick={this.deleteAnnotation}
-          >
-            { !isNew ? 'Remove' : 'Cancel' }
-          </Button>
-          <div>
-            <Button
-              bsSize="sm"
-              disabled={!isValid}
-              onClick={this.applyAnnotation}
-            >
-              Apply
-            </Button>
-
-            <Button
-              bsSize="sm"
-              disabled={!isValid}
-              onClick={this.submitAnnotation}
-            >
-              OK
-            </Button>
-          </div>
-        </div>
-      </div>
-    );
-  }
-}
-AnnotationLayer.propTypes = propTypes;
-AnnotationLayer.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx b/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx
deleted file mode 100644
index 3e4cd24e31..0000000000
--- a/superset/assets/src/explore/components/controls/AnnotationLayerControl.jsx
+++ /dev/null
@@ -1,177 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { OverlayTrigger, Popover, ListGroup, ListGroupItem } from 'react-bootstrap';
-import { connect } from 'react-redux';
-import { getChartKey } from '../../exploreUtils';
-import { runAnnotationQuery } from '../../../chart/chartAction';
-import InfoTooltipWithTrigger from '../../../components/InfoTooltipWithTrigger';
-
-
-import AnnotationLayer from './AnnotationLayer';
-import { t } from '../../../locales';
-
-
-const propTypes = {
-  colorScheme: PropTypes.string.isRequired,
-  annotationError: PropTypes.object,
-  annotationQuery: PropTypes.object,
-  vizType: PropTypes.string,
-
-  validationErrors: PropTypes.array,
-  name: PropTypes.string.isRequired,
-  actions: PropTypes.object,
-  value: PropTypes.arrayOf(PropTypes.object),
-  onChange: PropTypes.func,
-  refreshAnnotationData: PropTypes.func,
-};
-
-const defaultProps = {
-  vizType: '',
-  value: [],
-  annotationError: {},
-  annotationQuery: {},
-  onChange: () => {},
-};
-
-class AnnotationLayerControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.addAnnotationLayer = this.addAnnotationLayer.bind(this);
-    this.removeAnnotationLayer = this.removeAnnotationLayer.bind(this);
-  }
-
-  componentWillReceiveProps(nextProps) {
-    const { name, annotationError, validationErrors, value } = nextProps;
-    if (Object.keys(annotationError).length && !validationErrors.length) {
-      this.props.actions.setControlValue(name, value, Object.keys(annotationError));
-    }
-    if (!Object.keys(annotationError).length && validationErrors.length) {
-      this.props.actions.setControlValue(name, value, []);
-    }
-  }
-
-  addAnnotationLayer(annotationLayer) {
-    const annotation = annotationLayer;
-    let annotations = this.props.value.slice();
-    const i = annotations.findIndex(x => x.name === (annotation.oldName || annotation.name));
-    delete annotation.oldName;
-    if (i > -1) {
-      annotations[i] = annotation;
-    } else {
-      annotations = annotations.concat(annotation);
-    }
-    this.props.refreshAnnotationData(annotation);
-    this.props.onChange(annotations);
-  }
-
-  removeAnnotationLayer(annotation) {
-    const annotations = this.props.value.slice()
-      .filter(x => x.name !== annotation.oldName);
-    this.props.onChange(annotations);
-  }
-
-  renderPopover(parent, annotation, error) {
-    const id = !annotation ? '_new' : annotation.name;
-    return (
-      <Popover
-        style={{ maxWidth: 'none' }}
-        title={annotation ? 'Edit Annotation Layer' : 'Add Annotation Layer'}
-        id={`annotation-pop-${id}`}
-      >
-        <AnnotationLayer
-          {...annotation}
-          error={error}
-          colorScheme={this.props.colorScheme}
-          vizType={this.props.vizType}
-          addAnnotationLayer={this.addAnnotationLayer}
-          removeAnnotationLayer={this.removeAnnotationLayer}
-          close={() => this.refs[parent].hide()}
-        />
-      </Popover>
-    );
-  }
-
-  renderInfo(anno) {
-    const { annotationError, annotationQuery } = this.props;
-    if (annotationQuery[anno.name]) {
-      return (
-        <i className="fa fa-refresh" style={{ color: 'orange' }} aria-hidden />
-      );
-    }
-    if (annotationError[anno.name]) {
-      return (
-        <InfoTooltipWithTrigger
-          label="validation-errors"
-          bsStyle="danger"
-          tooltip={annotationError[anno.name]}
-        />
-      );
-    }
-    if (!anno.show) {
-      return <span style={{ color: 'red' }}> Hidden </span>;
-    }
-    return '';
-  }
-
-  render() {
-    const annotations = this.props.value.map((anno, i) => (
-      <OverlayTrigger
-        key={i}
-        trigger="click"
-        rootClose
-        ref={`overlay-${i}`}
-        placement="right"
-        overlay={this.renderPopover(`overlay-${i}`, anno,
-          this.props.annotationError[anno.name])}
-      >
-        <ListGroupItem>
-          <span>{anno.name}</span>
-          <span style={{ float: 'right' }}>
-            {this.renderInfo(anno)}
-          </span>
-        </ListGroupItem>
-      </OverlayTrigger>
-    ));
-    return (
-      <div>
-        <ListGroup>
-          {annotations}
-          <OverlayTrigger
-            trigger="click"
-            rootClose
-            ref="overlay-new"
-            placement="right"
-            overlay={this.renderPopover('overlay-new')}
-          >
-            <ListGroupItem>
-              <i className="fa fa-plus" /> &nbsp; {t('Add Annotation Layer')}
-            </ListGroupItem>
-          </OverlayTrigger>
-        </ListGroup>
-      </div>
-    );
-  }
-}
-
-AnnotationLayerControl.propTypes = propTypes;
-AnnotationLayerControl.defaultProps = defaultProps;
-
-// Tried to hook this up through stores/control.jsx instead of using redux
-// directly, could not figure out how to get access to the color_scheme
-function mapStateToProps({ charts, explore }) {
-  const chartKey = getChartKey(explore);
-  return {
-    colorScheme: (explore.controls || {}).color_scheme.value,
-    annotationError: charts[chartKey].annotationError,
-    annotationQuery: charts[chartKey].annotationQuery,
-    vizType: explore.controls.viz_type.value,
-  };
-}
-
-function mapDispatchToProps(dispatch) {
-  return {
-    refreshAnnotationData: annotationLayer => dispatch(runAnnotationQuery(annotationLayer)),
-  };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AnnotationLayerControl);
diff --git a/superset/assets/src/explore/components/controls/BoundsControl.jsx b/superset/assets/src/explore/components/controls/BoundsControl.jsx
deleted file mode 100644
index 803a539619..0000000000
--- a/superset/assets/src/explore/components/controls/BoundsControl.jsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Col, Row, FormGroup, FormControl } from 'react-bootstrap';
-import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-
-const propTypes = {
-  onChange: PropTypes.func,
-  value: PropTypes.array,
-};
-
-const defaultProps = {
-  onChange: () => {},
-  value: [null, null],
-};
-
-export default class BoundsControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {
-      minMax: [
-        props.value[0] === null ? '' : props.value[0],
-        props.value[1] === null ? '' : props.value[1],
-      ],
-    };
-    this.onChange = this.onChange.bind(this);
-    this.onMinChange = this.onMinChange.bind(this);
-    this.onMaxChange = this.onMaxChange.bind(this);
-  }
-  onMinChange(event) {
-    this.setState({
-      minMax: [
-        event.target.value,
-        this.state.minMax[1],
-      ],
-    }, this.onChange);
-  }
-  onMaxChange(event) {
-    this.setState({
-      minMax: [
-        this.state.minMax[0],
-        event.target.value,
-      ],
-    }, this.onChange);
-  }
-  onChange() {
-    const mm = this.state.minMax;
-    const errors = [];
-    if (mm[0] && isNaN(mm[0])) {
-      errors.push(t('`Min` value should be numeric or empty'));
-    }
-    if (mm[1] && isNaN(mm[1])) {
-      errors.push(t('`Max` value should be numeric or empty'));
-    }
-    if (errors.length === 0) {
-      this.props.onChange([parseFloat(mm[0]), parseFloat(mm[1])], errors);
-    } else {
-      this.props.onChange([null, null], errors);
-    }
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <FormGroup bsSize="small">
-          <Row>
-            <Col xs={6}>
-              <FormControl
-                type="text"
-                placeholder={t('Min')}
-                onChange={this.onMinChange}
-                value={this.state.minMax[0]}
-              />
-            </Col>
-            <Col xs={6}>
-              <FormControl
-                type="text"
-                placeholder={t('Max')}
-                onChange={this.onMaxChange}
-                value={this.state.minMax[1]}
-              />
-            </Col>
-          </Row>
-        </FormGroup>
-      </div>
-    );
-  }
-}
-
-BoundsControl.propTypes = propTypes;
-BoundsControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/CheckboxControl.jsx b/superset/assets/src/explore/components/controls/CheckboxControl.jsx
deleted file mode 100644
index a4138e483e..0000000000
--- a/superset/assets/src/explore/components/controls/CheckboxControl.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import ControlHeader from '../ControlHeader';
-import Checkbox from '../../../components/Checkbox';
-
-const propTypes = {
-  name: PropTypes.string.isRequired,
-  value: PropTypes.bool,
-  label: PropTypes.string,
-  description: PropTypes.string,
-  onChange: PropTypes.func,
-};
-
-const defaultProps = {
-  value: false,
-  onChange: () => {},
-};
-
-const checkboxStyle = { paddingRight: '5px' };
-
-export default class CheckboxControl extends React.Component {
-  onChange() {
-    this.props.onChange(!this.props.value);
-  }
-  render() {
-    return (
-      <ControlHeader
-        {...this.props}
-        leftNode={
-          <Checkbox
-            onChange={this.onChange.bind(this)}
-            style={checkboxStyle}
-            checked={!!this.props.value}
-          />
-        }
-      />
-    );
-  }
-}
-
-CheckboxControl.propTypes = propTypes;
-CheckboxControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/CollectionControl.jsx b/superset/assets/src/explore/components/controls/CollectionControl.jsx
deleted file mode 100644
index b545072bb3..0000000000
--- a/superset/assets/src/explore/components/controls/CollectionControl.jsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { ListGroup, ListGroupItem } from 'react-bootstrap';
-import shortid from 'shortid';
-import {
-  SortableContainer, SortableHandle, SortableElement, arrayMove,
-} from 'react-sortable-hoc';
-
-import InfoTooltipWithTrigger from '../../../components/InfoTooltipWithTrigger';
-import ControlHeader from '../ControlHeader';
-import controlMap from './';
-
-const propTypes = {
-  name: PropTypes.string.isRequired,
-  label: PropTypes.string,
-  description: PropTypes.string,
-  placeholder: PropTypes.string,
-  addTooltip: PropTypes.string,
-  itemGenerator: PropTypes.func,
-  keyAccessor: PropTypes.func,
-  onChange: PropTypes.func,
-  value: PropTypes.oneOfType([
-    PropTypes.array,
-  ]),
-  isFloat: PropTypes.bool,
-  isInt: PropTypes.bool,
-  controlName: PropTypes.string.isRequired,
-};
-
-const defaultProps = {
-  label: null,
-  description: null,
-  onChange: () => {},
-  placeholder: 'Empty collection',
-  itemGenerator: () => ({ key: shortid.generate() }),
-  keyAccessor: o => o.key,
-  value: [],
-  addTooltip: 'Add an item',
-};
-const SortableListGroupItem = SortableElement(ListGroupItem);
-const SortableListGroup = SortableContainer(ListGroup);
-const SortableDragger = SortableHandle(() => (
-  <i className="fa fa-bars text-primary" style={{ cursor: 'ns-resize' }} />));
-
-export default class CollectionControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onAdd = this.onAdd.bind(this);
-  }
-  onChange(i, value) {
-    Object.assign(this.props.value[i], value);
-    this.props.onChange(this.props.value);
-  }
-  onAdd() {
-    this.props.onChange(this.props.value.concat([this.props.itemGenerator()]));
-  }
-  onSortEnd({ oldIndex, newIndex }) {
-    this.props.onChange(arrayMove(this.props.value, oldIndex, newIndex));
-  }
-  removeItem(i) {
-    this.props.onChange(this.props.value.filter((o, ix) => i !== ix));
-  }
-  renderList() {
-    if (this.props.value.length === 0) {
-      return <div className="text-muted">{this.props.placeholder}</div>;
-    }
-    const Control = controlMap[this.props.controlName];
-    return (
-      <SortableListGroup
-        useDragHandle
-        lockAxis="y"
-        onSortEnd={this.onSortEnd.bind(this)}
-      >
-        {this.props.value.map((o, i) => (
-          <SortableListGroupItem
-            className="clearfix"
-            key={this.props.keyAccessor(o)}
-            index={i}
-          >
-            <div className="pull-left m-r-5">
-              <SortableDragger />
-            </div>
-            <div className="pull-left">
-              <Control
-                {...o}
-                onChange={this.onChange.bind(this, i)}
-              />
-            </div>
-            <div className="pull-right">
-              <InfoTooltipWithTrigger
-                icon="times"
-                label="remove-item"
-                tooltip="remove item"
-                bsStyle="primary"
-                onClick={this.removeItem.bind(this, i)}
-              />
-            </div>
-          </SortableListGroupItem>))}
-      </SortableListGroup>
-    );
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        {this.renderList()}
-        <InfoTooltipWithTrigger
-          icon="plus-circle"
-          label="add-item"
-          tooltip={this.props.addTooltip}
-          bsStyle="primary"
-          className="fa-lg"
-          onClick={this.onAdd}
-        />
-      </div>
-    );
-  }
-}
-
-CollectionControl.propTypes = propTypes;
-CollectionControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/ColorPickerControl.jsx b/superset/assets/src/explore/components/controls/ColorPickerControl.jsx
deleted file mode 100644
index ecccc8e33c..0000000000
--- a/superset/assets/src/explore/components/controls/ColorPickerControl.jsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { OverlayTrigger, Popover } from 'react-bootstrap';
-import { SketchPicker } from 'react-color';
-
-import ControlHeader from '../ControlHeader';
-import { bnbColors } from '../../../modules/colors';
-
-const propTypes = {
-  onChange: PropTypes.func,
-  value: PropTypes.object,
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-const swatchCommon = {
-  position: 'absolute',
-  width: '50px',
-  height: '20px',
-  top: '0px',
-  left: '0px',
-  right: '0px',
-  bottom: '0px',
-};
-
-const styles = {
-  swatch: {
-    width: '50px',
-    height: '20px',
-    position: 'relative',
-    padding: '5px',
-    borderRadius: '1px',
-    display: 'inline-block',
-    cursor: 'pointer',
-    boxShadow: 'rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset, rgba(0, 0, 0, 0.25) 0px 0px 4px inset',
-  },
-  color: {
-    ...swatchCommon,
-    borderRadius: '2px',
-  },
-  checkboard: {
-    ...swatchCommon,
-    background: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==") left center',
-  },
-};
-export default class ColorPickerControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onChange = this.onChange.bind(this);
-  }
-  onChange(col) {
-    this.props.onChange(col.rgb);
-  }
-  renderPopover() {
-    return (
-      <Popover id="filter-popover" className="color-popover">
-        <SketchPicker
-          color={this.props.value}
-          onChange={this.onChange}
-          presetColors={bnbColors.filter((s, i) => i < 7)}
-        />
-      </Popover>);
-  }
-  render() {
-    const c = this.props.value || { r: 0, g: 0, b: 0, a: 0 };
-    const colStyle = Object.assign(
-      {}, styles.color, { background: `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})` });
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <div style={styles.swatch}>
-            <div style={styles.checkboard} />
-            <div style={colStyle} />
-          </div>
-        </OverlayTrigger>
-      </div>
-    );
-  }
-}
-
-ColorPickerControl.propTypes = propTypes;
-ColorPickerControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx b/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx
deleted file mode 100644
index 14702d8442..0000000000
--- a/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Creatable } from 'react-select';
-import ControlHeader from '../ControlHeader';
-
-import { colorScalerFactory } from '../../../modules/colors';
-
-const propTypes = {
-  description: PropTypes.string,
-  label: PropTypes.string.isRequired,
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  value: PropTypes.string,
-  default: PropTypes.string,
-  choices: PropTypes.arrayOf(PropTypes.array).isRequired,
-  schemes: PropTypes.object.isRequired,
-  isLinear: PropTypes.bool,
-};
-
-const defaultProps = {
-  choices: [],
-  schemes: {},
-  onChange: () => {},
-};
-
-export default class ColorSchemeControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = {
-      scheme: this.props.value,
-    };
-
-    this.onChange = this.onChange.bind(this);
-    this.renderOption = this.renderOption.bind(this);
-  }
-
-  onChange(option) {
-    const optionValue = option ? option.value : null;
-    this.props.onChange(optionValue);
-    this.setState({ scheme: optionValue });
-  }
-
-  renderOption(key) {
-    const currentScheme = key.value ?
-      this.props.schemes[key.value] :
-      this.props.schemes[defaultProps.value];
-
-    let colors = currentScheme;
-    if (this.props.isLinear) {
-      const colorScaler = colorScalerFactory(currentScheme);
-      colors = [...Array(20).keys()].map(d => (colorScaler(d / 20)));
-    }
-
-    const list = colors.map((color, i) => (
-      <li
-        key={`${currentScheme}-${i}`}
-        style={{ backgroundColor: color, border: `1px solid ${color === 'white' ? 'black' : color}` }}
-      >&nbsp;</li>
-    ));
-    return (<ul className="color-scheme-container">{list}</ul>);
-  }
-
-  render() {
-    const selectProps = {
-      multi: false,
-      name: `select-${this.props.name}`,
-      placeholder: `Select (${this.props.choices.length})`,
-      default: this.props.default,
-      options: this.props.choices.map(choice => ({ value: choice[0], label: choice[1] })),
-      value: this.props.value,
-      autosize: false,
-      clearable: false,
-      onChange: this.onChange,
-      optionRenderer: this.renderOption,
-      valueRenderer: this.renderOption,
-    };
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <Creatable {...selectProps} />
-      </div>
-    );
-  }
-}
-
-ColorSchemeControl.propTypes = propTypes;
-ColorSchemeControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/DatasourceControl.jsx b/superset/assets/src/explore/components/controls/DatasourceControl.jsx
deleted file mode 100644
index 404ba5e329..0000000000
--- a/superset/assets/src/explore/components/controls/DatasourceControl.jsx
+++ /dev/null
@@ -1,223 +0,0 @@
-/* global notify */
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Table } from 'reactable';
-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,
-  label: PropTypes.string,
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  value: PropTypes.string.isRequired,
-  datasource: PropTypes.object,
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-export default class DatasourceControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = {
-      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.selectDatasource = this.selectDatasource.bind(this);
-  }
-  onChange(vizType) {
-    this.props.onChange(vizType);
-    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 });
-          notify.error(t('Something went wrong while fetching the datasource list'));
-        },
-      });
-    }
-  }
-  setSearchRef(searchRef) {
-    this.searchRef = searchRef;
-  }
-  toggleShowDatasource() {
-    this.setState({ showDatasource: !this.state.showDatasource });
-  }
-  toggleModal() {
-    this.setState({ showModal: !this.state.showModal });
-  }
-  changeSearch(event) {
-    this.setState({ filter: event.target.value });
-  }
-  selectDatasource(datasourceId) {
-    this.setState({ showModal: false });
-    this.props.onChange(datasourceId);
-  }
-  renderModal() {
-    return (
-      <Modal
-        show={this.state.showModal}
-        onHide={this.toggleModal}
-        onEnter={this.onEnterModal}
-        onExit={this.setSearchRef}
-        bsSize="lg"
-      >
-        <Modal.Header closeButton>
-          <Modal.Title>{t('Select a datasource')}</Modal.Title>
-        </Modal.Header>
-        <Modal.Body>
-          <div>
-            <FormControl
-              id="formControlsText"
-              inputRef={(ref) => { this.setSearchRef(ref); }}
-              type="text"
-              bsSize="sm"
-              value={this.state.filter}
-              placeholder={t('Search / Filter')}
-              onChange={this.changeSearch}
-            />
-          </div>
-          {this.state.loading &&
-            <img
-              className="loading"
-              alt="Loading..."
-              src="/static/assets/images/loading.gif"
-            />
-          }
-          {this.state.datasources &&
-            <Table
-              columns={['name', 'type', 'schema', 'connection', 'creator']}
-              className="table table-condensed"
-              data={this.state.datasources}
-              itemsPerPage={20}
-              filterable={['rawName', 'type', 'connection', 'schema', 'creator']}
-              filterBy={this.state.filter}
-              hideFilterInput
-            />
-          }
-        </Modal.Body>
-      </Modal>);
-  }
-  renderDatasource() {
-    const datasource = this.props.datasource;
-    return (
-      <div className="m-t-10">
-        <Well className="m-t-0">
-          <div className="m-b-10">
-            <Label>
-              <i className="fa fa-database" /> {datasource.database.backend}
-            </Label>
-            {` ${datasource.database.name} `}
-          </div>
-          <Row className="datasource-container">
-            <Col md={6}>
-              <strong>Columns</strong>
-              {datasource.columns.map(col => (
-                <div key={col.column_name}><ColumnOption showType column={col} /></div>
-              ))}
-            </Col>
-            <Col md={6}>
-              <strong>Metrics</strong>
-              {datasource.metrics.map(m => (
-                <div key={m.metric_name}><MetricOption metric={m} showType /></div>
-              ))}
-            </Col>
-          </Row>
-        </Well>
-      </div>);
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          placement="right"
-          overlay={
-            <Tooltip id={'error-tooltip'}>{t('Click to point to another datasource')}</Tooltip>
-          }
-        >
-          <Label onClick={this.toggleModal} style={{ cursor: 'pointer' }} className="m-r-5">
-            {this.props.datasource.name}
-          </Label>
-        </OverlayTrigger>
-        <OverlayTrigger
-          placement="right"
-          overlay={
-            <Tooltip id={'edit-datasource-tooltip'}>
-              {t('Edit the datasource\'s configuration')}
-            </Tooltip>
-          }
-        >
-          <a href={this.props.datasource.edit_url}>
-            <i className="fa fa-edit m-r-5" />
-          </a>
-        </OverlayTrigger>
-        <OverlayTrigger
-          placement="right"
-          overlay={
-            <Tooltip id={'toggle-datasource-tooltip'}>
-              {t('Show datasource configuration')}
-            </Tooltip>
-          }
-        >
-          <a href="#">
-            <i
-              className={`fa fa-${this.state.showDatasource ? 'minus' : 'plus'}-square m-r-5`}
-              onClick={this.toggleShowDatasource}
-            />
-          </a>
-        </OverlayTrigger>
-        <Collapse in={this.state.showDatasource}>
-          {this.renderDatasource()}
-        </Collapse>
-        {this.renderModal()}
-      </div>);
-  }
-}
-
-DatasourceControl.propTypes = propTypes;
-DatasourceControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/DateFilterControl.jsx b/superset/assets/src/explore/components/controls/DateFilterControl.jsx
deleted file mode 100644
index e22a32006c..0000000000
--- a/superset/assets/src/explore/components/controls/DateFilterControl.jsx
+++ /dev/null
@@ -1,219 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  Button, ButtonGroup, FormControl, InputGroup,
-  Label, OverlayTrigger, Popover, Glyphicon,
-} from 'react-bootstrap';
-import Select from 'react-select';
-import Datetime from 'react-datetime';
-import 'react-datetime/css/react-datetime.css';
-import moment from 'moment';
-
-import ControlHeader from '../ControlHeader';
-import PopoverSection from '../../../components/PopoverSection';
-
-const RELATIVE_TIME_OPTIONS = ['ago', 'from now'];
-const TIME_GRAIN_OPTIONS = ['seconds', 'minutes', 'hours', 'days', 'weeks', 'months', 'years'];
-
-const propTypes = {
-  animation: PropTypes.bool,
-  name: PropTypes.string.isRequired,
-  label: PropTypes.string,
-  description: PropTypes.string,
-  onChange: PropTypes.func,
-  value: PropTypes.string,
-  height: PropTypes.number,
-};
-
-const defaultProps = {
-  animation: true,
-  onChange: () => {},
-  value: '',
-};
-
-export default class DateFilterControl extends React.Component {
-  constructor(props) {
-    super(props);
-    const value = props.value || '';
-    this.state = {
-      num: '7',
-      grain: 'days',
-      rel: 'ago',
-      dttm: '',
-      type: 'free',
-      free: '',
-    };
-    const words = value.split(' ');
-    if (words.length >= 3 && RELATIVE_TIME_OPTIONS.indexOf(words[2]) >= 0) {
-      this.state.num = words[0];
-      this.state.grain = words[1];
-      this.state.rel = words[2];
-      this.state.type = 'rel';
-    } else if (moment(value).isValid()) {
-      this.state.dttm = value;
-      this.state.type = 'fix';
-    } else {
-      this.state.free = value;
-      this.state.type = 'free';
-    }
-  }
-  onControlChange(target, opt) {
-    this.setState({ [target]: opt.value });
-  }
-  onNumberChange(event) {
-    this.setState({ num: event.target.value });
-  }
-  onFreeChange(event) {
-    this.setState({ free: event.target.value });
-  }
-  setType(type) {
-    this.setState({ type });
-  }
-  setValueAndClose(val) {
-    this.setState({ type: 'free', free: val }, this.close);
-  }
-  setDatetime(dttm) {
-    this.setState({ dttm: dttm.format().substring(0, 19) });
-  }
-  close() {
-    let val;
-    if (this.state.type === 'rel') {
-      val = `${this.state.num} ${this.state.grain} ${this.state.rel}`;
-    } else if (this.state.type === 'fix') {
-      val = this.state.dttm;
-    } else if (this.state.type === 'free') {
-      val = this.state.free;
-    }
-    this.props.onChange(val);
-    this.refs.trigger.hide();
-  }
-  renderPopover() {
-    return (
-      <Popover id="filter-popover">
-        <div style={{ width: '250px' }}>
-          <PopoverSection
-            title="Fixed"
-            isSelected={this.state.type === 'fix'}
-            onSelect={this.setType.bind(this, 'fix')}
-          >
-            <InputGroup bsSize="small">
-              <InputGroup.Addon>
-                <Glyphicon glyph="calendar" />
-              </InputGroup.Addon>
-              <Datetime
-                inputProps={{ className: 'form-control input-sm' }}
-                dateFormat="YYYY-MM-DD"
-                defaultValue={this.state.dttm}
-                onFocus={this.setType.bind(this, 'fix')}
-                onChange={this.setDatetime.bind(this)}
-                timeFormat="h:mm:ss"
-              />
-            </InputGroup>
-          </PopoverSection>
-          <PopoverSection
-            title="Relative"
-            isSelected={this.state.type === 'rel'}
-            onSelect={this.setType.bind(this, 'rel')}
-          >
-            <div className="clearfix">
-              <div style={{ width: '50px' }} className="input-inline">
-                <FormControl
-                  onFocus={this.setType.bind(this, 'rel')}
-                  value={this.state.num}
-                  onChange={this.onNumberChange.bind(this)}
-                  bsSize="small"
-                />
-              </div>
-              <div style={{ width: '95px' }} className="input-inline">
-                <Select
-                  onFocus={this.setType.bind(this, 'rel')}
-                  value={this.state.grain}
-                  clearable={false}
-                  options={TIME_GRAIN_OPTIONS.map(s => ({ label: s, value: s }))}
-                  onChange={this.onControlChange.bind(this, 'grain')}
-                />
-              </div>
-              <div style={{ width: '95px' }} className="input-inline">
-                <Select
-                  value={this.state.rel}
-                  onFocus={this.setType.bind(this, 'rel')}
-                  clearable={false}
-                  options={RELATIVE_TIME_OPTIONS.map(s => ({ label: s, value: s }))}
-                  onChange={this.onControlChange.bind(this, 'rel')}
-                />
-              </div>
-            </div>
-          </PopoverSection>
-          <PopoverSection
-            title="Free form"
-            isSelected={this.state.type === 'free'}
-            onSelect={this.setType.bind(this, 'free')}
-            info={
-              'Superset supports smart date parsing. Strings like `last sunday` or ' +
-              '`last october` can be used.'
-            }
-          >
-            <FormControl
-              onFocus={this.setType.bind(this, 'free')}
-              value={this.state.free}
-              onChange={this.onFreeChange.bind(this)}
-              bsSize="small"
-            />
-          </PopoverSection>
-          <div className="clearfix">
-            <Button
-              bsSize="small"
-              className="float-left ok"
-              bsStyle="primary"
-              onClick={this.close.bind(this)}
-            >
-              Ok
-            </Button>
-            <ButtonGroup
-              className="float-right"
-            >
-              <Button
-                bsSize="small"
-                className="now"
-                onClick={this.setValueAndClose.bind(this, 'now')}
-              >
-                now
-              </Button>
-              <Button
-                bsSize="small"
-                className="clear"
-                onClick={this.setValueAndClose.bind(this, '')}
-              >
-                clear
-              </Button>
-            </ButtonGroup>
-          </div>
-        </div>
-      </Popover>
-    );
-  }
-  render() {
-    const value = this.props.value || '';
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          animation={this.props.animation}
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <Label style={{ cursor: 'pointer' }}>
-            {value.replace('T00:00:00', '') || '∞'}
-          </Label>
-        </OverlayTrigger>
-      </div>
-    );
-  }
-}
-
-DateFilterControl.propTypes = propTypes;
-DateFilterControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/FixedOrMetricControl.jsx b/superset/assets/src/explore/components/controls/FixedOrMetricControl.jsx
deleted file mode 100644
index df4eec0cb9..0000000000
--- a/superset/assets/src/explore/components/controls/FixedOrMetricControl.jsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Label, Popover, OverlayTrigger } from 'react-bootstrap';
-
-import controls from '../../controls';
-import TextControl from './TextControl';
-import SelectControl from './SelectControl';
-import ControlHeader from '../ControlHeader';
-import PopoverSection from '../../../components/PopoverSection';
-
-const controlTypes = {
-  fixed: 'fix',
-  metric: 'metric',
-};
-
-const propTypes = {
-  onChange: PropTypes.func,
-  value: PropTypes.object,
-  isFloat: PropTypes.bool,
-  datasource: PropTypes.object,
-  default: PropTypes.shape({
-    type: PropTypes.oneOf(['fix', 'metric']),
-    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-  }),
-};
-
-const defaultProps = {
-  onChange: () => {},
-  default: { type: controlTypes.fixed, value: 5 },
-};
-
-export default class FixedOrMetricControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onChange = this.onChange.bind(this);
-    this.setType = this.setType.bind(this);
-    this.setFixedValue = this.setFixedValue.bind(this);
-    this.setMetric = this.setMetric.bind(this);
-    const type = (props.value ? props.value.type : props.default.type) || controlTypes.fixed;
-    const value = (props.value ? props.value.value : props.default.value) || '100';
-    this.state = {
-      type,
-      fixedValue: type === controlTypes.fixed ? value : '',
-      metricValue: type === controlTypes.metric ? value : null,
-    };
-  }
-  onChange() {
-    this.props.onChange({
-      type: this.state.type,
-      value: this.state.type === controlTypes.fixed ?
-        this.state.fixedValue : this.state.metricValue,
-    });
-  }
-  setType(type) {
-    this.setState({ type }, this.onChange);
-  }
-  setFixedValue(fixedValue) {
-    this.setState({ fixedValue }, this.onChange);
-  }
-  setMetric(metricValue) {
-    this.setState({ metricValue }, this.onChange);
-  }
-  renderPopover() {
-    const value = this.props.value || this.props.default;
-    const type = value.type || controlTypes.fixed;
-    const metrics = this.props.datasource ? this.props.datasource.metrics : null;
-    return (
-      <Popover id="filter-popover">
-        <div style={{ width: '240px' }}>
-          <PopoverSection
-            title="Fixed"
-            isSelected={type === controlTypes.fixed}
-            onSelect={() => { this.onChange(controlTypes.fixed); }}
-          >
-            <TextControl
-              isFloat
-              onChange={this.setFixedValue}
-              onFocus={() => { this.setType(controlTypes.fixed); }}
-              value={this.state.fixedValue}
-            />
-          </PopoverSection>
-          <PopoverSection
-            title="Based on a metric"
-            isSelected={type === controlTypes.metric}
-            onSelect={() => { this.onChange(controlTypes.metric); }}
-          >
-            <SelectControl
-              {...controls.metric}
-              name="metric"
-              options={metrics}
-              onFocus={() => { this.setType(controlTypes.metric); }}
-              onChange={this.setMetric}
-              value={this.state.metricValue}
-            />
-          </PopoverSection>
-        </div>
-      </Popover>
-    );
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <Label style={{ cursor: 'pointer' }}>
-            {this.state.type === controlTypes.fixed &&
-              <span>{this.state.fixedValue}</span>
-            }
-            {this.state.type === controlTypes.metric &&
-              <span>
-                <span style={{ fontWeight: 'normal' }}>metric: </span>
-                <strong>{this.state.metricValue}</strong>
-              </span>
-            }
-          </Label>
-        </OverlayTrigger>
-      </div>
-    );
-  }
-}
-
-FixedOrMetricControl.propTypes = propTypes;
-FixedOrMetricControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/HiddenControl.jsx b/superset/assets/src/explore/components/controls/HiddenControl.jsx
deleted file mode 100644
index 3b1f445476..0000000000
--- a/superset/assets/src/explore/components/controls/HiddenControl.jsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FormControl } from 'react-bootstrap';
-
-const propTypes = {
-  onChange: PropTypes.func,
-  value: PropTypes.oneOfType([
-    PropTypes.string,
-    PropTypes.number,
-  ]),
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-export default function HiddenControl(props) {
-  // This wouldn't be necessary but might as well
-  return <FormControl type="hidden" value={props.value} />;
-}
-
-HiddenControl.propTypes = propTypes;
-HiddenControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/MetricsControl.jsx b/superset/assets/src/explore/components/controls/MetricsControl.jsx
deleted file mode 100644
index e93f6c1879..0000000000
--- a/superset/assets/src/explore/components/controls/MetricsControl.jsx
+++ /dev/null
@@ -1,263 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import VirtualizedSelect from 'react-virtualized-select';
-import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-import VirtualizedRendererWrap from '../../../components/VirtualizedRendererWrap';
-import OnPasteSelect from '../../../components/OnPasteSelect';
-import MetricDefinitionOption from '../MetricDefinitionOption';
-import MetricDefinitionValue from '../MetricDefinitionValue';
-import AdhocMetric from '../../AdhocMetric';
-import columnType from '../../propTypes/columnType';
-import savedMetricType from '../../propTypes/savedMetricType';
-import adhocMetricType from '../../propTypes/adhocMetricType';
-import {
-  AGGREGATES,
-  sqlaAutoGeneratedMetricNameRegex,
-  druidAutoGeneratedMetricRegex,
-} from '../../constants';
-
-const propTypes = {
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  value: PropTypes.oneOfType([
-    PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, adhocMetricType])),
-    PropTypes.oneOfType([PropTypes.string, adhocMetricType]),
-  ]),
-  columns: PropTypes.arrayOf(columnType),
-  savedMetrics: PropTypes.arrayOf(savedMetricType),
-  multi: PropTypes.bool,
-  datasourceType: PropTypes.string,
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-function isDictionaryForAdhocMetric(value) {
-  return value && !(value instanceof AdhocMetric) && value.expressionType;
-}
-
-// adhoc metrics are stored as dictionaries in URL params. We convert them back into the
-// AdhocMetric class for typechecking, consistency and instance method access.
-function coerceAdhocMetrics(value) {
-  if (!value) {
-    return [];
-  }
-  if (!Array.isArray(value)) {
-    if (isDictionaryForAdhocMetric(value)) {
-      return [new AdhocMetric(value)];
-    }
-    return [value];
-  }
-  return value.map((val) => {
-    if (isDictionaryForAdhocMetric(val)) {
-      return new AdhocMetric(val);
-    }
-    return val;
-  });
-}
-
-function getDefaultAggregateForColumn(column) {
-  const type = column.type;
-  if (typeof type !== 'string') {
-    return AGGREGATES.COUNT;
-  } else if (type === '' || type === 'expression') {
-    return AGGREGATES.SUM;
-  } else if (type.match(/.*char.*/i) || type.match(/string.*/i) || type.match(/.*text.*/i)) {
-    return AGGREGATES.COUNT_DISTINCT;
-  } else if (type.match(/.*int.*/i) || type === 'LONG' || type === 'DOUBLE' || type === 'FLOAT') {
-    return AGGREGATES.SUM;
-  } else if (type.match(/.*bool.*/i)) {
-    return AGGREGATES.MAX;
-  } else if (type.match(/.*time.*/i)) {
-    return AGGREGATES.COUNT;
-  } else if (type.match(/unknown/i)) {
-    return AGGREGATES.COUNT;
-  }
-  return null;
-}
-
-export default class MetricsControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.onChange = this.onChange.bind(this);
-    this.onMetricEdit = this.onMetricEdit.bind(this);
-    this.checkIfAggregateInInput = this.checkIfAggregateInInput.bind(this);
-    this.optionsForSelect = this.optionsForSelect.bind(this);
-    this.selectFilterOption = this.selectFilterOption.bind(this);
-    this.isAutoGeneratedMetric = this.isAutoGeneratedMetric.bind(this);
-    this.optionRenderer = VirtualizedRendererWrap(option => (
-      <MetricDefinitionOption option={option} />
-    ), { ignoreAutogeneratedMetrics: true });
-    this.valueRenderer = option => (
-      <MetricDefinitionValue
-        option={option}
-        onMetricEdit={this.onMetricEdit}
-        columns={this.props.columns}
-        multi={this.props.multi}
-        datasourceType={this.props.datasourceType}
-      />
-    );
-    this.refFunc = (ref) => {
-      if (ref) {
-        // eslint-disable-next-line no-underscore-dangle
-        this.select = ref._selectRef;
-      }
-    };
-    this.state = {
-      aggregateInInput: null,
-      options: this.optionsForSelect(this.props),
-      value: coerceAdhocMetrics(this.props.value),
-    };
-  }
-
-  componentWillReceiveProps(nextProps) {
-    if (
-      this.props.columns !== nextProps.columns ||
-      this.props.savedMetrics !== nextProps.savedMetrics
-    ) {
-      this.setState({ options: this.optionsForSelect(nextProps) });
-      this.props.onChange([]);
-    }
-    if (this.props.value !== nextProps.value) {
-      this.setState({ value: coerceAdhocMetrics(nextProps.value) });
-    }
-  }
-
-  onMetricEdit(changedMetric) {
-    let newValue = this.state.value.map((value) => {
-      if (value.optionName === changedMetric.optionName) {
-        return changedMetric;
-      }
-      return value;
-    });
-    if (!this.props.multi) {
-      newValue = newValue[0];
-    }
-    this.props.onChange(newValue);
-  }
-
-  onChange(opts) {
-    let transformedOpts = opts;
-    if (!this.props.multi) {
-      transformedOpts = [opts].filter(option => option);
-    }
-    let optionValues = transformedOpts.map((option) => {
-      if (option.metric_name) {
-        return option.metric_name;
-      } else if (option.column_name) {
-        const clearedAggregate = this.clearedAggregateInInput;
-        this.clearedAggregateInInput = null;
-        return new AdhocMetric({
-          column: option,
-          aggregate: clearedAggregate || getDefaultAggregateForColumn(option),
-        });
-      } else if (option instanceof AdhocMetric) {
-        return option;
-      } else if (option.aggregate_name) {
-        const newValue = `${option.aggregate_name}()`;
-        this.select.setInputValue(newValue);
-        this.select.handleInputChange({ target: { value: newValue } });
-        // we need to set a timeout here or the selectionWill be overwritten
-        // by some browsers (e.g. Chrome)
-        setTimeout(() => {
-          this.select.input.input.selectionStart = newValue.length - 1;
-          this.select.input.input.selectionEnd = newValue.length - 1;
-        }, 0);
-        return null;
-      }
-      return null;
-    }).filter(option => option);
-    if (!this.props.multi) {
-      optionValues = optionValues[0];
-    }
-    this.props.onChange(optionValues);
-  }
-
-  checkIfAggregateInInput(input) {
-    let nextState = { aggregateInInput: null };
-    Object.keys(AGGREGATES).forEach((aggregate) => {
-      if (input.toLowerCase().startsWith(aggregate.toLowerCase() + '(')) {
-        nextState = { aggregateInInput: aggregate };
-      }
-    });
-    this.clearedAggregateInInput = this.state.aggregateInInput;
-    this.setState(nextState);
-  }
-
-  optionsForSelect(props) {
-    const options = [
-      ...props.columns,
-      ...Object.keys(AGGREGATES).map(aggregate => ({ aggregate_name: aggregate })),
-      ...props.savedMetrics,
-    ];
-
-    return options.reduce((results, option) => {
-      if (option.metric_name) {
-        results.push({ ...option, optionName: option.metric_name });
-      } else if (option.column_name) {
-        results.push({ ...option, optionName: '_col_' + option.column_name });
-      } else if (option.aggregate_name) {
-        results.push({ ...option, optionName: '_aggregate_' + option.aggregate_name });
-      }
-      return results;
-    }, []);
-  }
-
-  isAutoGeneratedMetric(savedMetric) {
-    if (this.props.datasourceType === 'druid') {
-      return druidAutoGeneratedMetricRegex.test(savedMetric.verbose_name);
-    }
-    return sqlaAutoGeneratedMetricNameRegex.test(savedMetric.metric_name);
-  }
-
-  selectFilterOption(option, filterValue) {
-    if (this.state.aggregateInInput) {
-      let endIndex = filterValue.length;
-      if (filterValue.endsWith(')')) {
-        endIndex = filterValue.length - 1;
-      }
-      const valueAfterAggregate = filterValue.substring(filterValue.indexOf('(') + 1, endIndex);
-      return option.column_name &&
-        (option.column_name.toLowerCase().indexOf(valueAfterAggregate) >= 0);
-    }
-    return option.optionName &&
-      (!option.metric_name || !this.isAutoGeneratedMetric(option) || option.verbose_name) && (
-        option.optionName.toLowerCase().indexOf(filterValue) >= 0 ||
-        (
-          option.verbose_name && option.verbose_name.toLowerCase().indexOf(filterValue) >= 0
-        )
-      );
-  }
-
-  render() {
-    // TODO figure out why the dropdown isnt appearing as soon as a metric is selected
-    return (
-      <div className="metrics-select">
-        <ControlHeader {...this.props} />
-        <OnPasteSelect
-          multi={this.props.multi}
-          name={`select-${this.props.name}`}
-          placeholder={t('choose a column or aggregate function')}
-          options={this.state.options}
-          value={this.props.multi ? this.state.value : this.state.value[0]}
-          labelKey="label"
-          valueKey="optionName"
-          clearable
-          closeOnSelect
-          onChange={this.onChange}
-          optionRenderer={this.optionRenderer}
-          valueRenderer={this.valueRenderer}
-          onInputChange={this.checkIfAggregateInInput}
-          filterOption={this.selectFilterOption}
-          refFunc={this.refFunc}
-          selectWrap={VirtualizedSelect}
-        />
-      </div>
-    );
-  }
-}
-
-MetricsControl.propTypes = propTypes;
-MetricsControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx b/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
deleted file mode 100644
index ec5a365322..0000000000
--- a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-/* global notify */
-import React from 'react';
-import PropTypes from 'prop-types';
-import Select from '../../../components/AsyncSelect';
-import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-
-const propTypes = {
-  dataEndpoint: PropTypes.string.isRequired,
-  multi: PropTypes.bool,
-  mutator: PropTypes.func,
-  onAsyncErrorMessage: PropTypes.string,
-  onChange: PropTypes.func,
-  placeholder: PropTypes.string,
-  value: PropTypes.oneOfType([
-    PropTypes.string,
-    PropTypes.number,
-    PropTypes.arrayOf(PropTypes.string),
-    PropTypes.arrayOf(PropTypes.number),
-  ]),
-};
-
-const defaultProps = {
-  multi: true,
-  onAsyncErrorMessage: t('Error while fetching data'),
-  onChange: () => {},
-  placeholder: t('Select ...'),
-};
-
-const SelectAsyncControl = (props) => {
-  const { value, onChange, dataEndpoint, multi, mutator, placeholder, onAsyncErrorMessage } = props;
-  const onSelectionChange = (options) => {
-    const optionValues = options.map(option => option.value);
-    onChange(optionValues);
-  };
-
-  return (
-    <div>
-      <ControlHeader {...props} />
-      <Select
-        dataEndpoint={dataEndpoint}
-        onChange={onSelectionChange}
-        onAsyncError={errorMsg => notify.error(onAsyncErrorMessage + ': ' + errorMsg)}
-        mutator={mutator}
-        multi={multi}
-        value={value}
-        placeholder={placeholder}
-        valueRenderer={v => (<div>{v.label}</div>)}
-      />
-    </div>
-  );
-};
-
-SelectAsyncControl.propTypes = propTypes;
-SelectAsyncControl.defaultProps = defaultProps;
-
-export default SelectAsyncControl;
diff --git a/superset/assets/src/explore/components/controls/SelectControl.jsx b/superset/assets/src/explore/components/controls/SelectControl.jsx
deleted file mode 100644
index 4f1e8da469..0000000000
--- a/superset/assets/src/explore/components/controls/SelectControl.jsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import VirtualizedSelect from 'react-virtualized-select';
-import Select, { Creatable } from 'react-select';
-import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-import VirtualizedRendererWrap from '../../../components/VirtualizedRendererWrap';
-import OnPasteSelect from '../../../components/OnPasteSelect';
-
-const propTypes = {
-  choices: PropTypes.array,
-  clearable: PropTypes.bool,
-  description: PropTypes.string,
-  disabled: PropTypes.bool,
-  freeForm: PropTypes.bool,
-  isLoading: PropTypes.bool,
-  label: PropTypes.string,
-  multi: PropTypes.bool,
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  onFocus: PropTypes.func,
-  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
-  showHeader: PropTypes.bool,
-  optionRenderer: PropTypes.func,
-  valueRenderer: PropTypes.func,
-  valueKey: PropTypes.string,
-  options: PropTypes.array,
-  placeholder: PropTypes.string,
-  noResultsText: PropTypes.string,
-  refFunc: PropTypes.func,
-  filterOption: PropTypes.func,
-};
-
-const defaultProps = {
-  choices: [],
-  clearable: true,
-  description: null,
-  disabled: false,
-  freeForm: false,
-  isLoading: false,
-  label: null,
-  multi: false,
-  onChange: () => {},
-  onFocus: () => {},
-  showHeader: true,
-  optionRenderer: opt => opt.label,
-  valueRenderer: opt => opt.label,
-  valueKey: 'value',
-  noResultsText: t('No results found'),
-};
-
-export default class SelectControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = { options: this.getOptions(props) };
-    this.onChange = this.onChange.bind(this);
-  }
-  componentWillReceiveProps(nextProps) {
-    if (nextProps.choices !== this.props.choices ||
-        nextProps.options !== this.props.options) {
-      const options = this.getOptions(nextProps);
-      this.setState({ options });
-    }
-  }
-  onChange(opt) {
-    let optionValue = opt ? opt[this.props.valueKey] : null;
-    // if multi, return options values as an array
-    if (this.props.multi) {
-      optionValue = opt ? opt.map(o => o[this.props.valueKey]) : null;
-    }
-    this.props.onChange(optionValue);
-  }
-  getOptions(props) {
-    if (props.options) {
-      return props.options;
-    }
-    // Accepts different formats of input
-    const options = props.choices.map((c) => {
-      let option;
-      if (Array.isArray(c)) {
-        const label = c.length > 1 ? c[1] : c[0];
-        option = {
-          value: c[0],
-          label,
-        };
-      } else if (Object.is(c)) {
-        option = c;
-      } else {
-        option = {
-          value: c,
-          label: c,
-        };
-      }
-      return option;
-    });
-    if (props.freeForm) {
-      // For FreeFormSelect, insert value into options if not exist
-      const values = options.map(c => c.value);
-      if (props.value) {
-        let valuesToAdd = props.value;
-        if (!Array.isArray(valuesToAdd)) {
-          valuesToAdd = [valuesToAdd];
-        }
-        valuesToAdd.forEach((v) => {
-          if (values.indexOf(v) < 0) {
-            options.push({ value: v, label: v });
-          }
-        });
-      }
-    }
-    return options;
-  }
-  render() {
-    //  Tab, comma or Enter will trigger a new option created for FreeFormSelect
-    const placeholder = this.props.placeholder || t('%s option(s)', this.state.options.length);
-    const selectProps = {
-      multi: this.props.multi,
-      name: `select-${this.props.name}`,
-      placeholder,
-      options: this.state.options,
-      value: this.props.value,
-      labelKey: 'label',
-      valueKey: this.props.valueKey,
-      autosize: false,
-      clearable: this.props.clearable,
-      isLoading: this.props.isLoading,
-      onChange: this.onChange,
-      onFocus: this.props.onFocus,
-      optionRenderer: VirtualizedRendererWrap(this.props.optionRenderer),
-      valueRenderer: this.props.valueRenderer,
-      noResultsText: this.props.noResultsText,
-      selectComponent: this.props.freeForm ? Creatable : Select,
-      disabled: this.props.disabled,
-      refFunc: this.props.refFunc,
-      filterOption: this.props.filterOption,
-    };
-    return (
-      <div>
-        {this.props.showHeader &&
-          <ControlHeader {...this.props} />
-        }
-        <OnPasteSelect {...selectProps} selectWrap={VirtualizedSelect} />
-      </div>
-    );
-  }
-}
-
-SelectControl.propTypes = propTypes;
-SelectControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/SpatialControl.jsx b/superset/assets/src/explore/components/controls/SpatialControl.jsx
deleted file mode 100644
index d9db801c4b..0000000000
--- a/superset/assets/src/explore/components/controls/SpatialControl.jsx
+++ /dev/null
@@ -1,211 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  Row, Col, Button, Label, OverlayTrigger, Popover,
-} from 'react-bootstrap';
-import 'react-datetime/css/react-datetime.css';
-
-import ControlHeader from '../ControlHeader';
-import SelectControl from './SelectControl';
-import PopoverSection from '../../../components/PopoverSection';
-import Checkbox from '../../../components/Checkbox';
-import { t } from '../../../locales';
-
-const spatialTypes = {
-  latlong: 'latlong',
-  delimited: 'delimited',
-  geohash: 'geohash',
-};
-
-const propTypes = {
-  onChange: PropTypes.func,
-  value: PropTypes.object,
-  animation: PropTypes.bool,
-  choices: PropTypes.array,
-};
-
-const defaultProps = {
-  onChange: () => {},
-  animation: true,
-  choices: [],
-};
-
-export default class SpatialControl extends React.Component {
-  constructor(props) {
-    super(props);
-    const v = props.value || {};
-    let defaultCol;
-    if (props.choices.length > 0) {
-      defaultCol = props.choices[0][0];
-    }
-    this.state = {
-      type: v.type || spatialTypes.latlong,
-      delimiter: v.delimiter || ',',
-      latCol: v.latCol || defaultCol,
-      lonCol: v.lonCol || defaultCol,
-      lonlatCol: v.lonlatCol || defaultCol,
-      reverseCheckbox: v.reverseCheckbox || false,
-      geohashCol: v.geohashCol || defaultCol,
-      value: null,
-      errors: [],
-    };
-    this.toggleCheckbox = this.toggleCheckbox.bind(this);
-    this.onChange = this.onChange.bind(this);
-  }
-  componentDidMount() {
-    this.onChange();
-  }
-  onChange() {
-    const type = this.state.type;
-    const value = { type };
-    const errors = [];
-    const errMsg = t('Invalid lat/long configuration.');
-    if (type === spatialTypes.latlong) {
-      value.latCol = this.state.latCol;
-      value.lonCol = this.state.lonCol;
-      if (!value.lonCol || !value.latCol) {
-        errors.push(errMsg);
-      }
-    } else if (type === spatialTypes.delimited) {
-      value.lonlatCol = this.state.lonlatCol;
-      value.delimiter = this.state.delimiter;
-      value.reverseCheckbox = this.state.reverseCheckbox;
-      if (!value.lonlatCol || !value.delimiter) {
-        errors.push(errMsg);
-      }
-    } else if (type === spatialTypes.geohash) {
-      value.geohashCol = this.state.geohashCol;
-      if (!value.geohashCol) {
-        errors.push(errMsg);
-      }
-    }
-    this.setState({ value, errors });
-    this.props.onChange(value, errors);
-  }
-  setType(type) {
-    this.setState({ type }, this.onChange);
-  }
-  close() {
-    this.refs.trigger.hide();
-  }
-  toggleCheckbox() {
-    this.setState({ reverseCheckbox: !this.state.reverseCheckbox }, this.onChange);
-  }
-  renderLabelContent() {
-    if (this.state.errors.length > 0) {
-      return 'N/A';
-    }
-    if (this.state.type === spatialTypes.latlong) {
-      return `${this.state.lonCol} | ${this.state.latCol}`;
-    } else if (this.state.type === spatialTypes.delimited) {
-      return `${this.state.lonlatCol}`;
-    } else if (this.state.type === spatialTypes.geohash) {
-      return `${this.state.geohashCol}`;
-    }
-    return null;
-  }
-  renderSelect(name, type) {
-    return (
-      <SelectControl
-        name={name}
-        choices={this.props.choices}
-        value={this.state[name]}
-        clearable={false}
-        onFocus={() => {
-          this.setType(type);
-        }}
-        onChange={(value) => {
-          this.setState({ [name]: value }, this.onChange);
-        }}
-      />
-    );
-  }
-  renderPopover() {
-    return (
-      <Popover id="filter-popover">
-        <div style={{ width: '300px' }}>
-          <PopoverSection
-            title={t('Longitude & Latitude columns')}
-            isSelected={this.state.type === spatialTypes.latlong}
-            onSelect={this.setType.bind(this, spatialTypes.latlong)}
-          >
-            <Row>
-              <Col md={6}>
-                Longitude
-                {this.renderSelect('lonCol', spatialTypes.latlong)}
-              </Col>
-              <Col md={6}>
-                Latitude
-                {this.renderSelect('latCol', spatialTypes.latlong)}
-              </Col>
-            </Row>
-          </PopoverSection>
-          <PopoverSection
-            title={t('Delimited long & lat single column')}
-            info={t(
-              'Multiple formats accepted, look the geopy.points ' +
-              'Python library for more details')}
-            isSelected={this.state.type === spatialTypes.delimited}
-            onSelect={this.setType.bind(this, spatialTypes.delimited)}
-          >
-            <Row>
-              <Col md={6}>
-                Column
-                {this.renderSelect('lonlatCol', spatialTypes.delimited)}
-              </Col>
-              <Col md={6}>
-                {t('Reverse lat/long ')}
-                <Checkbox checked={this.state.reverseCheckbox} onChange={this.toggleCheckbox} />
-              </Col>
-            </Row>
-          </PopoverSection>
-          <PopoverSection
-            title={t('Geohash')}
-            isSelected={this.state.type === spatialTypes.geohash}
-            onSelect={this.setType.bind(this, spatialTypes.geohash)}
-          >
-            <Row>
-              <Col md={6}>
-                Column
-                {this.renderSelect('geohashCol', spatialTypes.geohash)}
-              </Col>
-            </Row>
-          </PopoverSection>
-          <div className="clearfix">
-            <Button
-              bsSize="small"
-              className="float-left ok"
-              bsStyle="primary"
-              onClick={this.close.bind(this)}
-            >
-              Ok
-            </Button>
-          </div>
-        </div>
-      </Popover>
-    );
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          animation={this.props.animation}
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <Label style={{ cursor: 'pointer' }}>
-            {this.renderLabelContent()}
-          </Label>
-        </OverlayTrigger>
-      </div>
-    );
-  }
-}
-
-SpatialControl.propTypes = propTypes;
-SpatialControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/TextAreaControl.jsx b/superset/assets/src/explore/components/controls/TextAreaControl.jsx
deleted file mode 100644
index 11c77a2cad..0000000000
--- a/superset/assets/src/explore/components/controls/TextAreaControl.jsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Button, FormGroup, FormControl } from 'react-bootstrap';
-
-import AceEditor from 'react-ace';
-import 'brace/mode/sql';
-import 'brace/mode/json';
-import 'brace/mode/html';
-import 'brace/mode/markdown';
-import 'brace/mode/javascript';
-
-import 'brace/theme/textmate';
-
-import ControlHeader from '../ControlHeader';
-import ModalTrigger from '../../../components/ModalTrigger';
-import { t } from '../../../locales';
-
-const propTypes = {
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  value: PropTypes.string,
-  height: PropTypes.number,
-  minLines: PropTypes.number,
-  maxLines: PropTypes.number,
-  offerEditInModal: PropTypes.bool,
-  language: PropTypes.oneOf([null, 'json', 'html', 'sql', 'markdown', 'javascript']),
-  aboveEditorSection: PropTypes.node,
-  readOnly: PropTypes.bool,
-};
-
-const defaultProps = {
-  onChange: () => {},
-  value: '',
-  height: 250,
-  minLines: 3,
-  maxLines: 10,
-  offerEditInModal: true,
-  readOnly: false,
-};
-
-export default class TextAreaControl extends React.Component {
-  onControlChange(event) {
-    this.props.onChange(event.target.value);
-  }
-  onAceChange(value) {
-    this.props.onChange(value);
-  }
-  renderEditor(inModal = false) {
-    if (this.props.language) {
-      return (
-        <AceEditor
-          mode={this.props.language}
-          theme="textmate"
-          style={{ border: '1px solid #CCC' }}
-          minLines={inModal ? 40 : this.props.minLines}
-          maxLines={inModal ? 1000 : this.props.maxLines}
-          onChange={this.onAceChange.bind(this)}
-          width="100%"
-          editorProps={{ $blockScrolling: true }}
-          enableLiveAutocompletion
-          value={this.props.value}
-          readOnly={this.props.readOnly}
-        />
-      );
-    }
-    return (
-      <FormGroup controlId="formControlsTextarea">
-        <FormControl
-          componentClass="textarea"
-          placeholder={t('textarea')}
-          onChange={this.onControlChange.bind(this)}
-          value={this.props.value}
-          disabled={this.props.readOnly}
-          style={{ height: this.props.height }}
-        />
-      </FormGroup>);
-  }
-  renderModalBody() {
-    return (
-      <div>
-        <div>{this.props.aboveEditorSection}</div>
-        {this.renderEditor(true)}
-      </div>
-    );
-  }
-  render() {
-    const controlHeader = <ControlHeader {...this.props} />;
-    return (
-      <div>
-        {controlHeader}
-        {this.renderEditor()}
-        {this.props.offerEditInModal &&
-          <ModalTrigger
-            bsSize="large"
-            modalTitle={controlHeader}
-            triggerNode={
-              <Button bsSize="small" className="m-t-5">
-                {t('Edit')} <strong>{this.props.language}</strong> {t('in modal')}
-              </Button>
-            }
-            modalBody={this.renderModalBody(true)}
-          />}
-      </div>
-    );
-  }
-}
-
-TextAreaControl.propTypes = propTypes;
-TextAreaControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/TextControl.jsx b/superset/assets/src/explore/components/controls/TextControl.jsx
deleted file mode 100644
index a43ffc8f56..0000000000
--- a/superset/assets/src/explore/components/controls/TextControl.jsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { FormGroup, FormControl } from 'react-bootstrap';
-import * as v from '../../validators';
-import ControlHeader from '../ControlHeader';
-
-const propTypes = {
-  onChange: PropTypes.func,
-  onFocus: PropTypes.func,
-  value: PropTypes.oneOfType([
-    PropTypes.string,
-    PropTypes.number,
-  ]),
-  isFloat: PropTypes.bool,
-  isInt: PropTypes.bool,
-  disabled: PropTypes.bool,
-};
-
-const defaultProps = {
-  onChange: () => {},
-  onFocus: () => {},
-  value: '',
-  isInt: false,
-  isFloat: false,
-  disabled: false,
-};
-
-export default class TextControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onChange = this.onChange.bind(this);
-  }
-  onChange(event) {
-    let value = event.target.value;
-
-    // Validation & casting
-    const errors = [];
-    if (value !== '' && this.props.isFloat) {
-      const error = v.numeric(value);
-      if (error) {
-        errors.push(error);
-      } else {
-        value = parseFloat(value);
-      }
-    }
-    if (value !== '' && this.props.isInt) {
-      const error = v.integer(value);
-      if (error) {
-        errors.push(error);
-      } else {
-        value = parseInt(value, 10);
-      }
-    }
-    this.props.onChange(value, errors);
-  }
-  render() {
-    const { value: rawValue } = this.props;
-    const value = typeof rawValue !== 'undefined' && rawValue !== null ? rawValue.toString() : '';
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <FormGroup controlId="formInlineName" bsSize="small">
-          <FormControl
-            type="text"
-            placeholder=""
-            onChange={this.onChange}
-            onFocus={this.props.onFocus}
-            value={value}
-            disabled={this.props.disabled}
-          />
-        </FormGroup>
-      </div>
-    );
-  }
-}
-
-TextControl.propTypes = propTypes;
-TextControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/TimeSeriesColumnControl.jsx b/superset/assets/src/explore/components/controls/TimeSeriesColumnControl.jsx
deleted file mode 100644
index 2634dd77b5..0000000000
--- a/superset/assets/src/explore/components/controls/TimeSeriesColumnControl.jsx
+++ /dev/null
@@ -1,232 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  Row, Col, FormControl, OverlayTrigger, Popover,
-} from 'react-bootstrap';
-import Select from 'react-select';
-
-import InfoTooltipWithTrigger from '../../../components/InfoTooltipWithTrigger';
-import BoundsControl from './BoundsControl';
-
-const propTypes = {
-  onChange: PropTypes.func,
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-const comparisonTypeOptions = [
-  { value: 'value', label: 'Actual value' },
-  { value: 'diff', label: 'Difference' },
-  { value: 'perc', label: 'Percentage' },
-  { value: 'perc_change', label: 'Percentage Change' },
-];
-
-const colTypeOptions = [
-  { value: 'time', label: 'Time Comparison' },
-  { value: 'contrib', label: 'Contribution' },
-  { value: 'spark', label: 'Sparkline' },
-  { value: 'avg', label: 'Period Average' },
-];
-
-export default class TimeSeriesColumnControl extends React.Component {
-  constructor(props) {
-    super(props);
-    const state = { ...props };
-    delete state.onChange;
-    this.state = state;
-    this.onChange = this.onChange.bind(this);
-  }
-  onChange() {
-    this.props.onChange(this.state);
-  }
-  onSelectChange(attr, opt) {
-    this.setState({ [attr]: opt.value }, this.onChange);
-  }
-  onTextInputChange(attr, event) {
-    this.setState({ [attr]: event.target.value }, this.onChange);
-  }
-  onBoundsChange(bounds) {
-    this.setState({ bounds }, this.onChange);
-  }
-  setType() {
-  }
-  textSummary() {
-    return `${this.state.label}`;
-  }
-  edit() {
-  }
-  formRow(label, tooltip, ttLabel, control) {
-    return (
-      <Row style={{ marginTop: '5px' }}>
-        <Col md={5}>
-          {`${label} `}
-          <InfoTooltipWithTrigger
-            placement="top"
-            tooltip={tooltip}
-            label={ttLabel}
-          />
-        </Col>
-        <Col md={7}>{control}</Col>
-      </Row>
-    );
-  }
-  renderPopover() {
-    return (
-      <Popover id="ts-col-popo" title="Column Configuration">
-        <div style={{ width: 300 }}>
-          {this.formRow(
-            'Label',
-            'The column header label',
-            'time-lag',
-            <FormControl
-              value={this.state.label}
-              onChange={this.onTextInputChange.bind(this, 'label')}
-              bsSize="small"
-              placeholder="Label"
-            />,
-          )}
-          {this.formRow(
-            'Tooltip',
-            'Column header tooltip',
-            'col-tooltip',
-            <FormControl
-              value={this.state.tooltip}
-              onChange={this.onTextInputChange.bind(this, 'tooltip')}
-              bsSize="small"
-              placeholder="Tooltip"
-            />,
-          )}
-          {this.formRow(
-            'Type',
-            'Type of comparison, value difference or percentage',
-            'col-type',
-            <Select
-              value={this.state.colType}
-              clearable={false}
-              onChange={this.onSelectChange.bind(this, 'colType')}
-              options={colTypeOptions}
-            />,
-          )}
-          <hr />
-          {this.state.colType === 'spark' && this.formRow(
-            'Width',
-            'Width of the sparkline',
-            'spark-width',
-            <FormControl
-              value={this.state.width}
-              onChange={this.onTextInputChange.bind(this, 'width')}
-              bsSize="small"
-              placeholder="Width"
-            />,
-          )}
-          {this.state.colType === 'spark' && this.formRow(
-            'Height',
-            'Height of the sparkline',
-            'spark-width',
-            <FormControl
-              value={this.state.height}
-              onChange={this.onTextInputChange.bind(this, 'height')}
-              bsSize="small"
-              placeholder="height"
-            />,
-          )}
-          {['time', 'avg'].indexOf(this.state.colType) >= 0 && this.formRow(
-            'Time Lag',
-            'Number of periods to compare against',
-            'time-lag',
-            <FormControl
-              value={this.state.timeLag}
-              onChange={this.onTextInputChange.bind(this, 'timeLag')}
-              bsSize="small"
-              placeholder="Time Lag"
-            />,
-          )}
-          {['spark'].indexOf(this.state.colType) >= 0 && this.formRow(
-            'Time Ratio',
-            'Number of periods to ratio against',
-            'time-ratio',
-            <FormControl
-              value={this.state.timeRatio}
-              onChange={this.onTextInputChange.bind(this, 'timeRatio')}
-              bsSize="small"
-              placeholder="Time Lag"
-            />,
-          )}
-          {this.state.colType === 'time' && this.formRow(
-            'Type',
-            'Type of comparison, value difference or percentage',
-            'comp-type',
-            <Select
-              value={this.state.comparisonType}
-              clearable={false}
-              onChange={this.onSelectChange.bind(this, 'comparisonType')}
-              options={comparisonTypeOptions}
-            />,
-          )}
-          {this.state.colType !== 'spark' && this.formRow(
-            'Color bounds',
-            (
-              `Number bounds used for color encoding from red to blue.
-              Reverse the numbers for blue to red. To get pure red or blue,
-              you can enter either only min or max.`
-            ),
-            'bounds',
-            <BoundsControl
-              value={this.state.bounds}
-              onChange={this.onBoundsChange.bind(this)}
-            />,
-          )}
-          {this.formRow(
-            'Number format',
-            'Optional d3 number format string',
-            'd3-format',
-            <FormControl
-              value={this.state.d3format}
-              onChange={this.onTextInputChange.bind(this, 'd3format')}
-              bsSize="small"
-              placeholder="Number format string"
-            />,
-          )}
-          {this.state.colType === 'spark' && this.formRow(
-            'Date format',
-            'Optional d3 date format string',
-            'date-format',
-            <FormControl
-              value={this.state.dateFormat}
-              onChange={this.onTextInputChange.bind(this, 'dateFormat')}
-              bsSize="small"
-              placeholder="Date format string"
-            />,
-          )}
-        </div>
-      </Popover>
-    );
-  }
-  render() {
-    return (
-      <span>
-        {this.textSummary()}{' '}
-        <OverlayTrigger
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <InfoTooltipWithTrigger
-            icon="edit"
-            className="text-primary"
-            onClick={this.edit.bind(this)}
-            label="edit-ts-column"
-          />
-        </OverlayTrigger>
-      </span>
-    );
-  }
-}
-
-TimeSeriesColumnControl.propTypes = propTypes;
-TimeSeriesColumnControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/ViewportControl.jsx b/superset/assets/src/explore/components/controls/ViewportControl.jsx
deleted file mode 100644
index 382b7f7173..0000000000
--- a/superset/assets/src/explore/components/controls/ViewportControl.jsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Label, Popover, OverlayTrigger } from 'react-bootstrap';
-import { decimal2sexagesimal } from 'geolib';
-
-import TextControl from './TextControl';
-import ControlHeader from '../ControlHeader';
-import { defaultViewport } from '../../../modules/geo';
-
-const PARAMS = [
-  'longitude',
-  'latitude',
-  'zoom',
-  'bearing',
-  'pitch',
-];
-
-const propTypes = {
-  onChange: PropTypes.func.isRequired,
-  value: PropTypes.shape({
-    longitude: PropTypes.number,
-    latitude: PropTypes.number,
-    zoom: PropTypes.number,
-    bearing: PropTypes.number,
-    pitch: PropTypes.number,
-  }),
-  default: PropTypes.object,
-  name: PropTypes.string.isRequired,
-};
-
-const defaultProps = {
-  onChange: () => {},
-  default: { type: 'fix', value: 5 },
-  value: defaultViewport,
-};
-
-export default class ViewportControl extends React.Component {
-  constructor(props) {
-    super(props);
-    this.onChange = this.onChange.bind(this);
-  }
-  onChange(ctrl, value) {
-    this.props.onChange({
-      ...this.props.value,
-      [ctrl]: value,
-    });
-  }
-  renderTextControl(ctrl) {
-    return (
-      <div key={ctrl}>
-        {ctrl}
-        <TextControl
-          value={this.props.value[ctrl]}
-          onChange={this.onChange.bind(this, ctrl)}
-          isFloat
-        />
-      </div>
-    );
-  }
-  renderPopover() {
-    return (
-      <Popover id={`filter-popover-${this.props.name}`} title="Viewport">
-        {PARAMS.map(ctrl => this.renderTextControl(ctrl))}
-      </Popover>
-    );
-  }
-  renderLabel() {
-    if (this.props.value.longitude && this.props.value.latitude) {
-      return (
-        decimal2sexagesimal(this.props.value.longitude) +
-        ' | ' +
-        decimal2sexagesimal(this.props.value.latitude)
-      );
-    }
-    return 'N/A';
-  }
-  render() {
-    return (
-      <div>
-        <ControlHeader {...this.props} />
-        <OverlayTrigger
-          container={document.body}
-          trigger="click"
-          rootClose
-          ref="trigger"
-          placement="right"
-          overlay={this.renderPopover()}
-        >
-          <Label style={{ cursor: 'pointer' }}>
-            {this.renderLabel()}
-          </Label>
-        </OverlayTrigger>
-      </div>
-    );
-  }
-}
-
-ViewportControl.propTypes = propTypes;
-ViewportControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/VizTypeControl.jsx b/superset/assets/src/explore/components/controls/VizTypeControl.jsx
deleted file mode 100644
index 74ba759c3f..0000000000
--- a/superset/assets/src/explore/components/controls/VizTypeControl.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {
-  Label, Row, Col, FormControl, Modal, OverlayTrigger,
-  Tooltip } from 'react-bootstrap';
-import visTypes from '../../visTypes';
-import ControlHeader from '../ControlHeader';
-import { t } from '../../../locales';
-
-const propTypes = {
-  description: PropTypes.string,
-  label: PropTypes.string,
-  name: PropTypes.string.isRequired,
-  onChange: PropTypes.func,
-  value: PropTypes.string.isRequired,
-};
-
-const defaultProps = {
-  onChange: () => {},
-};
-
-export default class VizTypeControl extends React.PureComponent {
-  constructor(props) {
-    super(props);
-    this.state = {
-      showModal: false,
-      filter: '',
-    };
-    this.toggleModal = this.toggleModal.bind(this);
-    this.changeSearch = this.changeSearch.bind(this);
-    this.setSearchRef = this.setSearchRef.bind(this);
-    this.focusSearch = this.focusSearch.bind(this);
-  }
-  onChange(vizType) {
-    this.props.onChange(vizType);
-    this.setState({ showModal: false });
-  }
-  setSearchRef(searchRef) {
-    this.searchRef = searchRef;
-  }
-  toggleModal() {
-    this.setState({ showModal: !this.state.showModal });
-  }
-  changeSearch(event) {
-    this.setState({ filter: event.target.value });
-  }
-  focusSearch() {
-    if (this.searchRef) {
-      this.searchRef.focus();
-    }
-  }
-  renderVizType(vizType) {
-    const vt = vizType;
-    return (
-      <div
-        className={`viztype-selector-container ${vt === this.props.value ? 'selected' : ''}`}
-        onClick={this.onChange.bind(this, vt)}
-      >
-        <img
-          alt={`viz-type-${vt}`}
-          width="100%"
-          className={`viztype-selector ${this.props.value === vt ? 'selected' : ''}`}
-          src={`/static/assets/images/viz_thumbnails/${vt}.png`}
-        />
-        <div className="viztype-label">
-          {visTypes[vt].label}
-        </div>
-      </div>);
-  }
-  render() {
-    const filter = this.state.filter;
-    const filteredVizTypes = Object.keys(visTypes)
-      .filter(vt => filter.length === 0 || visTypes[vt].label.toLowerCase().includes(filter));
-
-    const imgPerRow = 6;
-    const rows = [];
-    for (let i = 0; i <= filteredVizTypes.length; i += imgPerRow) {
-      rows.push(
-        <Row key={`row-${i}`}>
-          {filteredVizTypes.slice(i, i + imgPerRow).map(vt => (
-            <Col md={12 / imgPerRow} key={`grid-col-${vt}`}>
-              {this.renderVizType(vt)}
-            </Col>
-          ))}
-        </Row>);
-    }
-    return (
-      <div>
-        <ControlHeader
-          {...this.props}
-        />
-        <OverlayTrigger
-          placement="right"
-          overlay={
-            <Tooltip id={'error-tooltip'}>Click to change visualization type</Tooltip>
-          }
-        >
-          <Label onClick={this.toggleModal} style={{ cursor: 'pointer' }}>
-            {visTypes[this.props.value].label}
-          </Label>
-        </OverlayTrigger>
-        <Modal
-          show={this.state.showModal}
-          onHide={this.toggleModal}
-          onEnter={this.focusSearch}
-          onExit={this.setSearchRef}
-          bsSize="lg"
-        >
-          <Modal.Header closeButton>
-            <Modal.Title>{t('Select a visualization type')}</Modal.Title>
-          </Modal.Header>
-          <Modal.Body>
-            <div>
-              <FormControl
-                id="formControlsText"
-                inputRef={(ref) => { this.setSearchRef(ref); }}
-                type="text"
-                bsSize="sm"
-                value={this.state.filter}
-                placeholder={t('Search / Filter')}
-                onChange={this.changeSearch}
-              />
-            </div>
-            {rows}
-          </Modal.Body>
-        </Modal>
-      </div>);
-  }
-}
-
-VizTypeControl.propTypes = propTypes;
-VizTypeControl.defaultProps = defaultProps;
diff --git a/superset/assets/src/explore/components/controls/index.js b/superset/assets/src/explore/components/controls/index.js
deleted file mode 100644
index 4a2df4237b..0000000000
--- a/superset/assets/src/explore/components/controls/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import AnnotationLayerControl from './AnnotationLayerControl';
-import BoundsControl from './BoundsControl';
-import CheckboxControl from './CheckboxControl';
-import CollectionControl from './CollectionControl';
-import ColorPickerControl from './ColorPickerControl';
-import ColorSchemeControl from './ColorSchemeControl';
-import DatasourceControl from './DatasourceControl';
-import DateFilterControl from './DateFilterControl';
-import FixedOrMetricControl from './FixedOrMetricControl';
-import HiddenControl from './HiddenControl';
-import SelectAsyncControl from './SelectAsyncControl';
-import SelectControl from './SelectControl';
-import SpatialControl from './SpatialControl';
-import TextAreaControl from './TextAreaControl';
-import TextControl from './TextControl';
-import TimeSeriesColumnControl from './TimeSeriesColumnControl';
-import ViewportControl from './ViewportControl';
-import VizTypeControl from './VizTypeControl';
-import MetricsControl from './MetricsControl';
-import AdhocFilterControl from './AdhocFilterControl';
-
-const controlMap = {
-  AnnotationLayerControl,
-  BoundsControl,
-  CheckboxControl,
-  CollectionControl,
-  ColorPickerControl,
-  ColorSchemeControl,
-  DatasourceControl,
-  DateFilterControl,
-  FixedOrMetricControl,
-  HiddenControl,
-  SelectAsyncControl,
-  SelectControl,
-  SpatialControl,
-  TextAreaControl,
-  TextControl,
-  TimeSeriesColumnControl,
-  ViewportControl,
-  VizTypeControl,
-  MetricsControl,
-  AdhocFilterControl,
-};
-export default controlMap;
diff --git a/superset/assets/src/explore/constants.js b/superset/assets/src/explore/constants.js
deleted file mode 100644
index 39d7063782..0000000000
--- a/superset/assets/src/explore/constants.js
+++ /dev/null
@@ -1,37 +0,0 @@
-export const AGGREGATES = {
-  AVG: 'AVG',
-  COUNT: 'COUNT ',
-  COUNT_DISTINCT: 'COUNT_DISTINCT',
-  MAX: 'MAX',
-  MIN: 'MIN',
-  SUM: 'SUM',
-};
-
-export const OPERATORS = {
-  '==': '==',
-  '!=': '!=',
-  '>': '>',
-  '<': '<',
-  '>=': '>=',
-  '<=': '<=',
-  in: 'in',
-  'not in': 'not in',
-  LIKE: 'LIKE',
-  regex: 'regex',
-};
-
-export const TABLE_ONLY_OPERATORS = [OPERATORS.LIKE];
-export const DRUID_ONLY_OPERATORS = [OPERATORS.regex];
-export const HAVING_OPERATORS = [
-  OPERATORS['=='],
-  OPERATORS['!='],
-  OPERATORS['>'],
-  OPERATORS['<'],
-  OPERATORS['>='],
-  OPERATORS['<='],
-];
-export const MULTI_OPERATORS = [OPERATORS.in, OPERATORS['not in']];
-
-export const sqlaAutoGeneratedMetricNameRegex = /^(sum|min|max|avg|count|count_distinct)__.*$/i;
-export const sqlaAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|AVG|MAX|MIN|COUNT)\([A-Z0-9_."]*\)$/i;
-export const druidAutoGeneratedMetricRegex = /^(LONG|DOUBLE|FLOAT)?(SUM|MAX|MIN|COUNT)\([A-Z0-9_."]*\)$/i;
diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx
index 0281fe10b2..ecd18c4985 100644
--- a/superset/assets/src/explore/controls.jsx
+++ b/superset/assets/src/explore/controls.jsx
@@ -44,7 +44,7 @@ import {
   formatSelectOptions,
   mainMetric,
 } from '../modules/utils';
-import * as v from './validators';
+import * as v from '../controls/validators';
 import { colorPrimary, ALL_COLOR_SCHEMES, spectrums } from '../modules/colors';
 import { defaultViewport } from '../modules/geo';
 import ColumnOption from '../components/ColumnOption';
diff --git a/superset/assets/src/explore/propTypes/adhocFilterType.js b/superset/assets/src/explore/propTypes/adhocFilterType.js
deleted file mode 100644
index d09e4f81ec..0000000000
--- a/superset/assets/src/explore/propTypes/adhocFilterType.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import PropTypes from 'prop-types';
-
-import { OPERATORS } from '../constants';
-import { EXPRESSION_TYPES, CLAUSES }  from '../AdhocFilter';
-
-export default PropTypes.oneOfType([
-  PropTypes.shape({
-    expressionType: PropTypes.oneOf([EXPRESSION_TYPES.SIMPLE]).isRequired,
-    clause: PropTypes.oneOf([CLAUSES.HAVING, CLAUSES.WHERE]).isRequired,
-    subject: PropTypes.string.isRequired,
-    operator: PropTypes.oneOf(Object.keys(OPERATORS)).isRequired,
-    comparator: PropTypes.oneOfType([
-      PropTypes.string,
-      PropTypes.arrayOf(PropTypes.string),
-    ]).isRequired,
-  }),
-  PropTypes.shape({
-    expressionType: PropTypes.oneOf([EXPRESSION_TYPES.SQL]).isRequired,
-    clause: PropTypes.oneOf([CLAUSES.WHERE, CLAUSES.HAVING]).isRequired,
-    sqlExpression: PropTypes.string.isRequired,
-  }),
-]);
diff --git a/superset/assets/src/explore/propTypes/adhocMetricType.js b/superset/assets/src/explore/propTypes/adhocMetricType.js
deleted file mode 100644
index 3887d046db..0000000000
--- a/superset/assets/src/explore/propTypes/adhocMetricType.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import PropTypes from 'prop-types';
-
-import { AGGREGATES } from '../constants';
-import columnType from './columnType';
-import { EXPRESSION_TYPES }  from '../AdhocMetric';
-
-export default PropTypes.oneOfType([
-  PropTypes.shape({
-    expressionType: PropTypes.oneOf([EXPRESSION_TYPES.SIMPLE]).isRequired,
-    column: columnType.isRequired,
-    aggregate: PropTypes.oneOf(Object.keys(AGGREGATES)).isRequired,
-    label: PropTypes.string.isRequired,
-  }),
-  PropTypes.shape({
-    expressionType: PropTypes.oneOf([EXPRESSION_TYPES.SQL]).isRequired,
-    sqlExpression: PropTypes.string.isRequired,
-    label: PropTypes.string.isRequired,
-  }),
-]);
diff --git a/superset/assets/src/explore/propTypes/aggregateOptionType.js b/superset/assets/src/explore/propTypes/aggregateOptionType.js
deleted file mode 100644
index 0a5eebfa32..0000000000
--- a/superset/assets/src/explore/propTypes/aggregateOptionType.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import PropTypes from 'prop-types';
-
-export default PropTypes.shape({
-  aggregate_name: PropTypes.string.isRequired,
-});
diff --git a/superset/assets/src/explore/propTypes/columnType.js b/superset/assets/src/explore/propTypes/columnType.js
deleted file mode 100644
index 5ff33e590a..0000000000
--- a/superset/assets/src/explore/propTypes/columnType.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import PropTypes from 'prop-types';
-
-export default PropTypes.shape({
-  column_name: PropTypes.string.isRequired,
-  type: PropTypes.string,
-});
diff --git a/superset/assets/src/explore/propTypes/savedMetricType.js b/superset/assets/src/explore/propTypes/savedMetricType.js
deleted file mode 100644
index 3e713a85d7..0000000000
--- a/superset/assets/src/explore/propTypes/savedMetricType.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import PropTypes from 'prop-types';
-
-export default PropTypes.shape({
-  metric_name: PropTypes.string.isRequired,
-  expression: PropTypes.string.isRequired,
-});
diff --git a/superset/assets/src/explore/validators.js b/superset/assets/src/explore/validators.js
deleted file mode 100644
index b1625d476f..0000000000
--- a/superset/assets/src/explore/validators.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Reusable validator functions used in controls definitions
- *
- * validator functions receive the v and the configuration of the control
- * as arguments and return something that evals to false if v is valid,
- * and an error message if not valid.
- * */
-import { t } from '../locales';
-
-export function numeric(v) {
-  if (v && isNaN(v)) {
-    return t('is expected to be a number');
-  }
-  return false;
-}
-
-export function integer(v) {
-  if (v && (isNaN(v) || parseInt(v, 10) !== +(v))) {
-    return t('is expected to be an integer');
-  }
-  return false;
-}
-
-export function nonEmpty(v) {
-  if (
-      v === null ||
-      v === undefined ||
-      v === '' ||
-      (Array.isArray(v) && v.length === 0)
-  ) {
-    return t('cannot be empty');
-  }
-  return false;
-}
diff --git a/superset/assets/src/explore/visTypes.js b/superset/assets/src/explore/visTypes.js
index b0037ec5f4..46d193919e 100644
--- a/superset/assets/src/explore/visTypes.js
+++ b/superset/assets/src/explore/visTypes.js
@@ -3,7 +3,7 @@
  * and associated with each and every visualization type.
  */
 import { D3_TIME_FORMAT_OPTIONS } from './controls';
-import * as v from './validators';
+import * as v from '../controls/validators';
 import { t } from '../locales';
 
 export const sections = {
diff --git a/superset/assets/src/visualizations/filter_box.jsx b/superset/assets/src/visualizations/filter_box.jsx
index ea9cbdc39a..755163b6dc 100644
--- a/superset/assets/src/visualizations/filter_box.jsx
+++ b/superset/assets/src/visualizations/filter_box.jsx
@@ -7,9 +7,9 @@ import VirtualizedSelect from 'react-virtualized-select';
 import { Creatable } from 'react-select';
 import { Button } from 'react-bootstrap';
 
-import DateFilterControl from '../explore/components/controls/DateFilterControl';
+import DateFilterControl from '../controls/controls/DateFilterControl';
 import ControlRow from '../explore/components/ControlRow';
-import Control from '../explore/components/Control';
+import Control from '../controls/Control';
 import controls from '../explore/controls';
 import OnPasteSelect from '../components/OnPasteSelect';
 import VirtualizedRendererWrap from '../components/VirtualizedRendererWrap';


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org