This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 9fe30ab  style: Pass at propagating (and enhancing) Button component 
throughout Superset (#10649)
9fe30ab is described below

commit 9fe30ab71e01ba427d91fb3cd76f5535148a010f
Author: Evan Rusackas <[email protected]>
AuthorDate: Fri Aug 28 17:34:28 2020 -0700

    style: Pass at propagating (and enhancing) Button component throughout 
Superset (#10649)
    
    * getting rid of weird focus/active outline ring
    
    * Buttons... buttons _everywhere_
    
    * linting
    
    * Nixing views/CRUD/dataset/Button component
    
    * fixing 2 typing errors
    
    * fixing more TS errors
    
    * prefer src path for include
    
    * one more real button, one less CSS class
    
    * one more "button" to "Button"
    
    * Published Status is now a proper clickable Label
    
    * nixing the CRUD button again
    
    * touching up stories, with SupersetButton story
    
    * SIP-34 button colors
    
    * adding polished package to mix colors
    
    * updating button colors to match Superset theme
    
    * abstracting away from bootstrap-specific props (might pivot libraries 
soon!)
    
    * more abstraction from bsStyle/bsSize props
    
    * exchanging styles for a prop
    
    * linting
    
    * restoring feature flag to stock
    
    * using src alias
    
    * last <button> replacement
    
    * this classname would never be applied
    
    * more linting action
    
    * fixing unsupported bsSize 'medium', and cta typing error
    
    * more cta action
    
    * unnecessary styles
    
    * errant bsSize prop
    
    * cleanup
    
    * tweaks to make new New button work
    
    * Linting
    
    * fixing a couple tests
    
    * fixing theme based test failure
    
    * margin tweak for NEW button
    
    * another fixed test
    
    * another fixed test
    
    * fixing two more tests
    
    * fixing last broken tests.
    
    * always be linting
    
    * Adding tertiary/dashed buttons
    
    * cleaning up QueryAndSave buttons
    
    * fixing "link" button styles
    
    * fixing/updating link button styles
    
    * cta buttons on Modal component
    
    * linting.
    
    * exporting button story knobs, making ALL knobs safe for export.
    
    * capitalizing a file... no big whoop
    
    * Basic button tests
    
    * renaming button - temporarily
    
    * renaming file to fix capitalization issue
    
    * passing theme through to a difficult popover.
    
    * fixin' a newly busted unit test
    
    * lint fixin'
    
    * oops, shouldn't have changed this prop!
    
    * adding a dive() to themedShallow, and fixing a cypress/jest test
    
    * addressing lint stuff
    
    * touching up stories, with SupersetButton story
    
    * SIP-34 button colors
    
    * updating button colors to match Superset theme
    
    * abstracting away from bootstrap-specific props (might pivot libraries 
soon!)
    
    * linting
    
    * restoring feature flag to stock
    
    * cleanup
    
    * Linting
    
    * renaming button - temporarily
    
    * renaming file to fix capitalization issue
    
    * oops, shouldn't have changed this prop!
    
    * adding a dive() to themedShallow, and fixing a cypress/jest test
    
    * addressing lint stuff
    
    * nixing new modal button
    
    * Fixing another popover/button issue that should break cypress
    
    * lint :sparkles:
    
    * passing classNames through to new button (should fix some tests)
    
    * cleaning unused classes, making cypress tests use data attrs
    
    * fixin' the test
    
    * fixing another class-based test with data-test attr
    
    * no longer passing theme as prop to buttons in popovers... themeprovider 
is better
    
    * outline/border tweaks!
---
 .../integration/explore/AdhocFilters.test.ts       |   4 +-
 .../integration/explore/AdhocMetrics.test.ts       |   8 +-
 .../cypress/integration/explore/advanced.test.ts   |   4 +-
 .../cypress/integration/explore/control.test.ts    |   2 +-
 superset-frontend/package-lock.json                |   8 +-
 superset-frontend/package.json                     |   1 +
 superset-frontend/spec/helpers/theming.ts          |   2 +-
 .../addSlice/AddSliceContainer_spec.tsx            |  14 +-
 .../components/ConfirmStatusChange_spec.jsx        |   6 +-
 .../components/gridComponents/Tab_spec.jsx         |   2 +-
 .../datasource/DatasourceModal_spec.jsx            |   5 +-
 .../components/AdhocFilterEditPopover_spec.jsx     |   7 +-
 .../explore/components/AdhocFilterOption_spec.jsx  |   4 +-
 .../components/AdhocMetricEditPopover_spec.jsx     |   7 +-
 .../explore/components/AdhocMetricOption_spec.jsx  |   4 +-
 .../explore/components/DateFilterControl_spec.jsx  |   2 +-
 .../explore/components/QueryAndSaveBtns_spec.jsx   |   2 +-
 .../explore/components/SaveModal_spec.jsx          |   6 +-
 .../spec/javascripts/sqllab/QuerySearch_spec.jsx   |   2 +-
 .../spec/javascripts/sqllab/SouthPane_spec.jsx     |   2 +-
 superset-frontend/src/CRUD/CollectionTable.tsx     |   4 +-
 .../SqlLab/components/EstimateQueryCostButton.jsx  |   6 +-
 .../SqlLab/components/ExploreCtasResultsButton.jsx |   4 +-
 .../src/SqlLab/components/ExploreResultsButton.jsx |   6 +-
 .../src/SqlLab/components/LimitControl.tsx         |  15 +-
 .../src/SqlLab/components/QuerySearch.jsx          |   6 +-
 .../src/SqlLab/components/QueryTable.jsx           |  22 +-
 .../src/SqlLab/components/ResultSet.tsx            |  19 +-
 .../src/SqlLab/components/RunQueryActionButton.tsx |  14 +-
 .../src/SqlLab/components/SaveQuery.jsx            |   6 +-
 .../src/SqlLab/components/ScheduleQueryButton.jsx  |   2 +-
 .../src/SqlLab/components/ShareSqlLabQuery.jsx     |   4 +-
 .../src/SqlLab/components/SqlEditor.jsx            |   4 +-
 .../src/SqlLab/components/SqlEditorLeftBar.jsx     |   8 +-
 .../src/SqlLab/components/TemplateParamsEditor.jsx |   2 +-
 .../src/addSlice/AddSliceContainer.tsx             |   5 +-
 superset-frontend/src/common/components/Modal.tsx  |   2 +-
 .../{button.stories.jsx => Button.stories.jsx}     |  73 +++----
 .../src/components/Button/Button.test.tsx          |  68 ++++++
 superset-frontend/src/components/Button/index.tsx  | 232 ++++++++++++++++++---
 .../src/components/ErrorMessage/ErrorAlert.tsx     |   8 +-
 .../src/components/ExpandableList.tsx              |   4 +-
 .../src/components/Label/Label.stories.tsx         |   2 +-
 .../src/components/ListView/ListView.tsx           |   3 +-
 superset-frontend/src/components/Menu/Menu.tsx     |   8 +
 superset-frontend/src/components/Menu/NewMenu.tsx  |  13 +-
 superset-frontend/src/components/Menu/SubMenu.tsx  |  14 +-
 superset-frontend/src/components/Modal.tsx         |  12 +-
 superset-frontend/src/components/ModalTrigger.jsx  |   8 +-
 .../src/components/RefreshChartOverlay.tsx         |   2 +-
 .../dashboard/components/DeleteComponentModal.jsx  |   4 +-
 .../src/dashboard/components/Header.jsx            |  22 +-
 .../src/dashboard/components/PropertiesModal.jsx   |  18 +-
 .../src/dashboard/components/PublishedStatus.jsx   |  23 +-
 .../dashboard/components/RefreshIntervalModal.jsx  |   7 +-
 .../src/dashboard/components/SaveModal.jsx         |   5 +-
 .../components/filterscope/FilterScopeSelector.jsx |   6 +-
 .../src/dashboard/stylesheets/buttons.less         |  11 -
 .../src/datasource/DatasourceEditor.jsx            |   2 +-
 .../src/datasource/DatasourceModal.tsx             |  14 +-
 .../explore/components/AdhocFilterEditPopover.jsx  | 124 ++++++-----
 .../src/explore/components/AdhocFilterOption.jsx   |  10 +-
 .../explore/components/AdhocMetricEditPopover.jsx  | 188 +++++++++--------
 .../src/explore/components/AdhocMetricOption.jsx   |   9 +-
 .../src/explore/components/DisplayQueryButton.jsx  |   2 +-
 .../explore/components/ExploreActionButtons.jsx    |   2 +-
 .../src/explore/components/PropertiesModal.tsx     |  10 +-
 .../src/explore/components/QueryAndSaveBtns.jsx    |  28 +--
 .../src/explore/components/SaveModal.jsx           |  25 +--
 .../components/controls/AnnotationLayer.jsx        |  20 +-
 .../components/controls/AnnotationLayerControl.jsx |   7 +-
 .../components/controls/DateFilterControl.jsx      |   9 +-
 .../explore/components/controls/SpatialControl.jsx |   7 +-
 .../components/controls/TextAreaControl.jsx        |   5 +-
 .../src/views/CRUD/data/dataset/Button.tsx         |  72 -------
 .../src/visualizations/FilterBox/FilterBox.jsx     |   6 +-
 superset-frontend/stylesheets/superset.less        |   4 +
 .../SqlLab/components/ExploreCtasResultsButton.jsx |   4 +-
 78 files changed, 755 insertions(+), 557 deletions(-)

diff --git 
a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts
 
b/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts
index dc12961..576304a 100644
--- 
a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts
+++ 
b/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts
@@ -40,7 +40,7 @@ describe('AdhocFilters', () => {
       cy.get('button').contains('Save').click();
     });
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({
       waitAlias: '@postJson',
       chartSelector: 'svg',
@@ -63,7 +63,7 @@ describe('AdhocFilters', () => {
       cy.get('button').contains('Save').click();
     });
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({
       waitAlias: '@postJson',
       chartSelector: 'svg',
diff --git 
a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts
 
b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts
index 59722a0..5dfd741 100644
--- 
a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts
+++ 
b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts
@@ -48,7 +48,7 @@ describe('AdhocMetrics', () => {
 
     cy.get('.metrics-select .metric-option').contains(metricName);
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({
       waitAlias: '@postJson',
       querySubstring: `${metric} AS "${metricName}"`, // SQL statement
@@ -77,7 +77,7 @@ describe('AdhocMetrics', () => {
       .type('/COUNT(DISTINCT name)', { force: true });
     cy.get('#metrics-edit-popover').find('button').contains('Save').click();
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
 
     const metric = 'SUM(num)/COUNT(DISTINCT name)';
     cy.verifySliceSuccess({
@@ -103,7 +103,7 @@ describe('AdhocMetrics', () => {
       cy.get('button').contains('Save').click();
     });
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
 
     const metric = 'SUM(num)';
     cy.verifySliceSuccess({
@@ -124,7 +124,7 @@ describe('AdhocMetrics', () => {
     });
 
     const metric = 'AVG(sum_boys)';
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({
       waitAlias: '@postJson',
       querySubstring: `${metric} AS "${metric}"`,
diff --git 
a/superset-frontend/cypress-base/cypress/integration/explore/advanced.test.ts 
b/superset-frontend/cypress-base/cypress/integration/explore/advanced.test.ts
index 624bac6..31291e3 100644
--- 
a/superset-frontend/cypress-base/cypress/integration/explore/advanced.test.ts
+++ 
b/superset-frontend/cypress-base/cypress/integration/explore/advanced.test.ts
@@ -43,7 +43,7 @@ describe('Advanced analytics', () => {
       .find('.Select__multi-value__label')
       .contains('364 days');
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.wait('@postJson');
     cy.reload();
     cy.verifySliceSuccess({
@@ -90,7 +90,7 @@ describe('Annotations', () => {
       cy.get('button').contains('OK').click();
     });
 
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({
       waitAlias: '@postJson',
       chartSelector: 'svg',
diff --git 
a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts 
b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
index f906958..7a08611 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
@@ -78,7 +78,7 @@ describe('Groupby control', () => {
       cy.get('.Select__control').click();
       cy.get('input[type=text]').type('state{enter}');
     });
-    cy.get('button.query').click();
+    cy.get('button[data-test="run-query-button"]').click();
     cy.verifySliceSuccess({ waitAlias: '@postJson', chartSelector: 'svg' });
   });
 });
diff --git a/superset-frontend/package-lock.json 
b/superset-frontend/package-lock.json
index 18da52a..ecc9c29 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -34830,16 +34830,14 @@
       "version": "3.6.5",
       "resolved": "https://registry.npmjs.org/polished/-/polished-3.6.5.tgz";,
       "integrity": 
"sha512-VwhC9MlhW7O5dg/z7k32dabcAFW1VI2+7fSe8cE/kXcfL7mVdoa5UxciYGW2sJU78ldDLT6+ROEKIZKFNTnUXQ==",
-      "dev": true,
       "requires": {
         "@babel/runtime": "^7.9.2"
       },
       "dependencies": {
         "@babel/runtime": {
-          "version": "7.10.5",
-          "resolved": 
"https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.5.tgz";,
-          "integrity": 
"sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==",
-          "dev": true,
+          "version": "7.11.2",
+          "resolved": 
"https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz";,
+          "integrity": 
"sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
           "requires": {
             "regenerator-runtime": "^0.13.4"
           }
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index cb00328..4302995 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -145,6 +145,7 @@
     "mousetrap": "^1.6.1",
     "mustache": "^2.2.1",
     "omnibar": "^2.1.1",
+    "polished": "^3.6.5",
     "prop-types": "^15.7.2",
     "re-resizable": "^4.3.1",
     "react": "^16.13.1",
diff --git a/superset-frontend/spec/helpers/theming.ts 
b/superset-frontend/spec/helpers/theming.ts
index cf1b462..7f83165 100644
--- a/superset-frontend/spec/helpers/theming.ts
+++ b/superset-frontend/spec/helpers/theming.ts
@@ -51,5 +51,5 @@ export function styledShallow(
       theme: supersetTheme,
       ...options?.wrappingComponentProps,
     },
-  });
+  }).dive();
 }
diff --git 
a/superset-frontend/spec/javascripts/addSlice/AddSliceContainer_spec.tsx 
b/superset-frontend/spec/javascripts/addSlice/AddSliceContainer_spec.tsx
index 5db740d..4af7fec 100644
--- a/superset-frontend/spec/javascripts/addSlice/AddSliceContainer_spec.tsx
+++ b/superset-frontend/spec/javascripts/addSlice/AddSliceContainer_spec.tsx
@@ -18,7 +18,7 @@
  */
 import React from 'react';
 import { shallow, ShallowWrapper } from 'enzyme';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Select from 'src/components/Select';
 import AddSliceContainer, {
   AddSliceContainerProps,
@@ -58,9 +58,9 @@ describe('AddSliceContainer', () => {
   });
 
   it('renders a disabled button if no datasource is selected', () => {
-    expect(
-      wrapper.find(Button).dive().find('.btn[disabled=true]'),
-    ).toHaveLength(1);
+    expect(wrapper.find(Button).dive().find({ disabled: true })).toHaveLength(
+      1,
+    );
   });
 
   it('renders an enabled button if datasource is selected', () => {
@@ -70,9 +70,9 @@ describe('AddSliceContainer', () => {
       datasourceId: datasourceValue.split('__')[0],
       datasourceType: datasourceValue.split('__')[1],
     });
-    expect(
-      wrapper.find(Button).dive().find('.btn[disabled=false]'),
-    ).toHaveLength(1);
+    expect(wrapper.find(Button).dive().find({ disabled: true })).toHaveLength(
+      0,
+    );
   });
 
   it('formats explore url', () => {
diff --git 
a/superset-frontend/spec/javascripts/components/ConfirmStatusChange_spec.jsx 
b/superset-frontend/spec/javascripts/components/ConfirmStatusChange_spec.jsx
index a9e027d..4b00263 100644
--- a/superset-frontend/spec/javascripts/components/ConfirmStatusChange_spec.jsx
+++ b/superset-frontend/spec/javascripts/components/ConfirmStatusChange_spec.jsx
@@ -18,7 +18,7 @@
  */
 import React from 'react';
 import { mount } from 'enzyme';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { supersetTheme, ThemeProvider } from '@superset-ui/style';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import Modal from 'src/components/Modal';
@@ -33,7 +33,7 @@ describe('ConfirmStatusChange', () => {
     <ConfirmStatusChange {...mockedProps}>
       {confirm => (
         <>
-          <button id="btn1" onClick={confirm} />
+          <Button id="btn1" onClick={confirm} />
         </>
       )}
     </ConfirmStatusChange>,
@@ -44,7 +44,7 @@ describe('ConfirmStatusChange', () => {
   );
 
   it('opens a confirm modal', () => {
-    wrapper.find('#btn1').props().onClick('foo');
+    wrapper.find('#btn1').first().props().onClick('foo');
 
     wrapper.update();
 
diff --git 
a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx
 
b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx
index 0d07255..059de56 100644
--- 
a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx
@@ -18,7 +18,7 @@
  */
 import { Provider } from 'react-redux';
 import React from 'react';
-import { mount } from 'enzyme';
+import { styledMount as mount } from 'spec/helpers/theming';
 import sinon from 'sinon';
 
 import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
diff --git 
a/superset-frontend/spec/javascripts/datasource/DatasourceModal_spec.jsx 
b/superset-frontend/spec/javascripts/datasource/DatasourceModal_spec.jsx
index be5111c..f8bf0c0 100644
--- a/superset-frontend/spec/javascripts/datasource/DatasourceModal_spec.jsx
+++ b/superset-frontend/spec/javascripts/datasource/DatasourceModal_spec.jsx
@@ -83,7 +83,10 @@ describe('DatasourceModal', () => {
 
   it('saves on confirm', async () => {
     act(() => {
-      wrapper.find('[className="m-r-5"]').props().onClick();
+      wrapper
+        .find('button[data-test="datasource-modal-save"]')
+        .props()
+        .onClick();
     });
     await waitForComponentToPaint(wrapper);
     act(() => {
diff --git 
a/superset-frontend/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
index 022ee1d..652c162 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/AdhocFilterEditPopover_spec.jsx
@@ -20,7 +20,8 @@
 import React from 'react';
 import sinon from 'sinon';
 import { shallow } from 'enzyme';
-import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
+import { Popover, Tab, Tabs } from 'react-bootstrap';
+import Button from 'src/components/Button';
 
 import AdhocFilter, {
   EXPRESSION_TYPES,
@@ -117,9 +118,9 @@ describe('AdhocFilterEditPopover', () => {
 
   it('highlights save if changes are present', () => {
     const { wrapper } = setup();
-    expect(wrapper.find(Button).find({ bsStyle: 'primary' })).not.toExist();
+    expect(wrapper.find(Button).find({ buttonStyle: 'primary' 
})).not.toExist();
     wrapper.instance().onAdhocFilterChange(sqlAdhocFilter);
-    expect(wrapper.find(Button).find({ bsStyle: 'primary' })).toExist();
+    expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist();
   });
 
   it('will initiate a drag when clicked', () => {
diff --git 
a/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
index f2e9ffe..118ef32 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx
@@ -19,7 +19,7 @@
 /* eslint-disable no-unused-expressions */
 import React from 'react';
 import sinon from 'sinon';
-import { shallow } from 'enzyme';
+import { styledShallow as shallow } from 'spec/helpers/theming';
 import { OverlayTrigger } from 'react-bootstrap';
 
 import Label from 'src/components/Label';
@@ -46,7 +46,7 @@ function setup(overrides) {
     datasource: {},
     ...overrides,
   };
-  const wrapper = shallow(<AdhocFilterOption {...props} />);
+  const wrapper = shallow(<AdhocFilterOption {...props} />).dive();
   return { wrapper };
 }
 
diff --git 
a/superset-frontend/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
index e66f6ae..2f15017 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/AdhocMetricEditPopover_spec.jsx
@@ -20,7 +20,8 @@
 import React from 'react';
 import sinon from 'sinon';
 import { shallow } from 'enzyme';
-import { Button, FormGroup, Popover } from 'react-bootstrap';
+import { FormGroup, Popover } from 'react-bootstrap';
+import Button from 'src/components/Button';
 
 import AdhocMetric, { EXPRESSION_TYPES } from 'src/explore/AdhocMetric';
 import AdhocMetricEditPopover from 
'src/explore/components/AdhocMetricEditPopover';
@@ -117,9 +118,9 @@ describe('AdhocMetricEditPopover', () => {
 
   it('highlights save if changes are present', () => {
     const { wrapper } = setup();
-    expect(wrapper.find(Button).find({ bsStyle: 'primary' })).not.toExist();
+    expect(wrapper.find(Button).find({ buttonStyle: 'primary' 
})).not.toExist();
     wrapper.instance().onColumnChange({ column: columns[1] });
-    expect(wrapper.find(Button).find({ bsStyle: 'primary' })).toExist();
+    expect(wrapper.find(Button).find({ buttonStyle: 'primary' })).toExist();
   });
 
   it('will initiate a drag when clicked', () => {
diff --git 
a/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
index 0612f6c..5b23da2 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx
@@ -19,7 +19,7 @@
 /* eslint-disable no-unused-expressions */
 import React from 'react';
 import sinon from 'sinon';
-import { shallow } from 'enzyme';
+import { styledShallow as shallow } from 'spec/helpers/theming';
 import { OverlayTrigger } from 'react-bootstrap';
 
 import Label from 'src/components/Label';
@@ -46,7 +46,7 @@ function setup(overrides) {
     columns,
     ...overrides,
   };
-  const wrapper = shallow(<AdhocMetricOption {...props} />);
+  const wrapper = shallow(<AdhocMetricOption {...props} />).dive();
   return { wrapper, onMetricEdit };
 }
 
diff --git 
a/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
index 5a93af1..693c869 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/DateFilterControl_spec.jsx
@@ -20,7 +20,7 @@
 import React from 'react';
 import sinon from 'sinon';
 import { styledMount as mount } from 'spec/helpers/theming';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 
 import Label from 'src/components/Label';
 import DateFilterControl from 
'src/explore/components/controls/DateFilterControl';
diff --git 
a/superset-frontend/spec/javascripts/explore/components/QueryAndSaveBtns_spec.jsx
 
b/superset-frontend/spec/javascripts/explore/components/QueryAndSaveBtns_spec.jsx
index 2126265..7c32361 100644
--- 
a/superset-frontend/spec/javascripts/explore/components/QueryAndSaveBtns_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/explore/components/QueryAndSaveBtns_spec.jsx
@@ -54,7 +54,7 @@ describe('QueryAndSaveButtons', () => {
     });
 
     it('calls onQuery when query button is clicked', () => {
-      const queryButton = wrapper.find('.query');
+      const queryButton = wrapper.find('[data-test="run-query-button"]');
       queryButton.simulate('click');
       expect(defaultProps.onQuery.called).toBe(true);
     });
diff --git 
a/superset-frontend/spec/javascripts/explore/components/SaveModal_spec.jsx 
b/superset-frontend/spec/javascripts/explore/components/SaveModal_spec.jsx
index 4348b9b..b419a7b 100644
--- a/superset-frontend/spec/javascripts/explore/components/SaveModal_spec.jsx
+++ b/superset-frontend/spec/javascripts/explore/components/SaveModal_spec.jsx
@@ -21,8 +21,10 @@ import configureStore from 'redux-mock-store';
 import thunk from 'redux-thunk';
 import { bindActionCreators } from 'redux';
 
-import { shallow, mount } from 'enzyme';
-import { FormControl, Modal, Button, Radio } from 'react-bootstrap';
+import { shallow } from 'enzyme';
+import { styledMount as mount } from 'spec/helpers/theming';
+import { FormControl, Modal, Radio } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import sinon from 'sinon';
 import fetchMock from 'fetch-mock';
 
diff --git a/superset-frontend/spec/javascripts/sqllab/QuerySearch_spec.jsx 
b/superset-frontend/spec/javascripts/sqllab/QuerySearch_spec.jsx
index 5d853dc..68ae9e8 100644
--- a/superset-frontend/spec/javascripts/sqllab/QuerySearch_spec.jsx
+++ b/superset-frontend/spec/javascripts/sqllab/QuerySearch_spec.jsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 import React from 'react';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { shallow } from 'enzyme';
 import sinon from 'sinon';
 
diff --git a/superset-frontend/spec/javascripts/sqllab/SouthPane_spec.jsx 
b/superset-frontend/spec/javascripts/sqllab/SouthPane_spec.jsx
index 64f0164..75a8519 100644
--- a/superset-frontend/spec/javascripts/sqllab/SouthPane_spec.jsx
+++ b/superset-frontend/spec/javascripts/sqllab/SouthPane_spec.jsx
@@ -78,7 +78,7 @@ describe('SouthPane', () => {
   const getWrapper = () =>
     shallow(<SouthPaneContainer {...mockedProps} />, {
       context: { store },
-    }).dive();
+    });
 
   let wrapper;
 
diff --git a/superset-frontend/src/CRUD/CollectionTable.tsx 
b/superset-frontend/src/CRUD/CollectionTable.tsx
index dfa89b0..11d3105 100644
--- a/superset-frontend/src/CRUD/CollectionTable.tsx
+++ b/superset-frontend/src/CRUD/CollectionTable.tsx
@@ -19,7 +19,7 @@
 import React, { ReactNode } from 'react';
 import shortid from 'shortid';
 import { t } from '@superset-ui/translation';
-import Button from '../components/Button';
+import Button from 'src/components/Button';
 import Fieldset from './Fieldset';
 import { recurseReactClone } from './utils';
 import './crud.less';
@@ -167,7 +167,7 @@ export default class CRUDCollection extends 
React.PureComponent<
           {allowDeletes && !allowAddItem && <th className="tiny-cell" />}
           {allowAddItem && (
             <th>
-              <Button bsStyle="primary" onClick={this.onAddItem}>
+              <Button buttonStyle="primary" onClick={this.onAddItem}>
                 <i className="fa fa-plus" /> {t('Add Item')}
               </Button>
             </th>
diff --git 
a/superset-frontend/src/SqlLab/components/EstimateQueryCostButton.jsx 
b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton.jsx
index 9de7808..69d0095 100644
--- a/superset-frontend/src/SqlLab/components/EstimateQueryCostButton.jsx
+++ b/superset-frontend/src/SqlLab/components/EstimateQueryCostButton.jsx
@@ -22,7 +22,7 @@ import { Table } from 'reactable-arc';
 import { Alert } from 'react-bootstrap';
 import { t } from '@superset-ui/translation';
 
-import Button from '../../components/Button';
+import Button from 'src/components/Button';
 import Loading from '../../components/Loading';
 import ModalTrigger from '../../components/ModalTrigger';
 
@@ -85,8 +85,8 @@ class EstimateQueryCostButton extends React.PureComponent {
           modalBody={this.renderModalBody()}
           triggerNode={
             <Button
-              bsStyle="warning"
-              bsSize="small"
+              buttonStyle="warning"
+              buttonSize="small"
               onClick={this.onClick}
               key="query-estimate-btn"
               tooltip={tooltip}
diff --git 
a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx 
b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
index 390bfbc..ff48a61 100644
--- a/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ExploreCtasResultsButton.jsx
@@ -24,9 +24,9 @@ import Dialog from 'react-bootstrap-dialog';
 import { t } from '@superset-ui/translation';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
 
+import Button from 'src/components/Button';
 import { exploreChart } from '../../explore/exploreUtils';
 import * as actions from '../actions/sqlLab';
-import Button from '../../components/Button';
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
@@ -89,7 +89,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
     return (
       <>
         <Button
-          bsSize="small"
+          buttonSize="small"
           onClick={this.onClick}
           tooltip={t('Explore the result set in the data exploration view')}
         >
diff --git a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx 
b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
index 8ecec6f..9a8cef6 100644
--- a/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ExploreResultsButton.jsx
@@ -25,11 +25,11 @@ import { Alert } from 'react-bootstrap';
 import Dialog from 'react-bootstrap-dialog';
 import { t } from '@superset-ui/translation';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
-
 import shortid from 'shortid';
+
+import Button from 'src/components/Button';
 import { exploreChart } from '../../explore/exploreUtils';
 import * as actions from '../actions/sqlLab';
-import Button from '../../components/Button';
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
@@ -213,7 +213,7 @@ class ExploreResultsButton extends React.PureComponent {
     return (
       <>
         <Button
-          bsSize="small"
+          buttonSize="small"
           onClick={this.onClick}
           disabled={!allowsSubquery}
           tooltip={t('Explore the result set in the data exploration view')}
diff --git a/superset-frontend/src/SqlLab/components/LimitControl.tsx 
b/superset-frontend/src/SqlLab/components/LimitControl.tsx
index 9b55dce..ee2750b 100644
--- a/superset-frontend/src/SqlLab/components/LimitControl.tsx
+++ b/superset-frontend/src/SqlLab/components/LimitControl.tsx
@@ -17,13 +17,8 @@
  * under the License.
  */
 import React from 'react';
-import {
-  Button,
-  FormGroup,
-  FormControl,
-  Overlay,
-  Popover,
-} from 'react-bootstrap';
+import { FormGroup, FormControl, Overlay, Popover } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 import styled from '@superset-ui/style';
 
@@ -119,8 +114,8 @@ export default class LimitControl extends 
React.PureComponent<
           </FormGroup>
           <div className="clearfix">
             <Button
-              bsSize="small"
-              bsStyle="primary"
+              buttonSize="small"
+              buttonStyle="primary"
               className="float-right ok m-l-5"
               disabled={!isValid}
               onClick={this.submitAndClose}
@@ -128,7 +123,7 @@ export default class LimitControl extends 
React.PureComponent<
               {t('Ok')}
             </Button>
             <Button
-              bsSize="small"
+              buttonSize="small"
               className="float-right reset"
               onClick={this.setValueAndClose.bind(
                 this,
diff --git a/superset-frontend/src/SqlLab/components/QuerySearch.jsx 
b/superset-frontend/src/SqlLab/components/QuerySearch.jsx
index d7f0e90..f75ed10 100644
--- a/superset-frontend/src/SqlLab/components/QuerySearch.jsx
+++ b/superset-frontend/src/SqlLab/components/QuerySearch.jsx
@@ -18,7 +18,7 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Select from 'src/components/Select';
 import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/connection';
@@ -273,8 +273,8 @@ class QuerySearch extends React.PureComponent {
             />
 
             <Button
-              bsSize="small"
-              bsStyle="success"
+              buttonSize="small"
+              buttonStyle="success"
               onClick={this.refreshQueries}
             >
               {t('Search')}
diff --git a/superset-frontend/src/SqlLab/components/QueryTable.jsx 
b/superset-frontend/src/SqlLab/components/QueryTable.jsx
index 6c3ec80..969bed8 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable.jsx
+++ b/superset-frontend/src/SqlLab/components/QueryTable.jsx
@@ -24,6 +24,7 @@ import { ProgressBar, Well } from 'react-bootstrap';
 import Label from 'src/components/Label';
 import { t } from '@superset-ui/translation';
 
+import Button from 'src/components/Button';
 import Link from '../../components/Link';
 import ResultSet from './ResultSet';
 import ModalTrigger from '../../components/ModalTrigger';
@@ -99,31 +100,34 @@ class QueryTable extends React.PureComponent {
           </div>
         );
         q.user = (
-          <button
-            className="btn btn-link btn-xs"
+          <Button
+            buttonSize="small"
+            buttonStyle="link"
             onClick={this.props.onUserClicked.bind(this, q.userId)}
           >
             {q.user}
-          </button>
+          </Button>
         );
         q.db = (
-          <button
-            className="btn btn-link btn-xs"
+          <Button
+            buttonSize="small"
+            buttonStyle="link"
             onClick={this.props.onDbClicked.bind(this, q.dbId)}
           >
             {q.db}
-          </button>
+          </Button>
         );
         q.started = moment(q.startDttm).format('HH:mm:ss');
         q.querylink = (
           <div style={{ width: '100px' }}>
-            <button
-              className="btn btn-link btn-xs"
+            <Button
+              buttonSize="small"
+              buttonStyle="link"
               onClick={this.openQuery.bind(this, q.queryId)}
             >
               <i className="fa fa-external-link m-r-3" />
               {t('Edit')}
-            </button>
+            </Button>
           </div>
         );
         q.sql = (
diff --git a/superset-frontend/src/SqlLab/components/ResultSet.tsx 
b/superset-frontend/src/SqlLab/components/ResultSet.tsx
index db154fb..db40267 100644
--- a/superset-frontend/src/SqlLab/components/ResultSet.tsx
+++ b/superset-frontend/src/SqlLab/components/ResultSet.tsx
@@ -17,7 +17,8 @@
  * under the License.
  */
 import React, { CSSProperties } from 'react';
-import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
+import { Alert, ButtonGroup, ProgressBar } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import shortid from 'shortid';
 import { t } from '@superset-ui/translation';
 
@@ -166,7 +167,7 @@ export default class ResultSet extends React.PureComponent<
               )}
             {this.props.csv && (
               <Button
-                bsSize="small"
+                buttonSize="small"
                 href={`/superset/csv/${this.props.query.id}`}
               >
                 <i className="fa fa-file-text-o" /> {t('.CSV')}
@@ -177,7 +178,7 @@ export default class ResultSet extends React.PureComponent<
               text={prepareCopyToClipboardTabularData(data)}
               wrapped={false}
               copyNode={
-                <Button bsSize="small">
+                <Button buttonSize="small">
                   <i className="fa fa-clipboard" /> {t('Clipboard')}
                 </Button>
               }
@@ -243,7 +244,7 @@ export default class ResultSet extends React.PureComponent<
             ] {t('was created')} &nbsp;
             <ButtonGroup>
               <Button
-                bsSize="small"
+                buttonSize="small"
                 className="m-r-5"
                 onClick={() => this.popSelectStar(tempSchema, tempTable)}
               >
@@ -296,9 +297,9 @@ export default class ResultSet extends React.PureComponent<
       if (query.isDataPreview) {
         return (
           <Button
-            bsSize="sm"
+            buttonSize="sm"
             className="fetch"
-            bsStyle="primary"
+            buttonStyle="primary"
             onClick={() =>
               this.reFetchQueryResults({
                 ...query,
@@ -312,9 +313,9 @@ export default class ResultSet extends React.PureComponent<
       } else if (query.resultsKey) {
         return (
           <Button
-            bsSize="sm"
+            buttonSize="sm"
             className="fetch"
-            bsStyle="primary"
+            buttonStyle="primary"
             onClick={() => this.fetchResults(query)}
           >
             {t('Refetch Results')}
@@ -336,7 +337,7 @@ export default class ResultSet extends React.PureComponent<
     if (query.trackingUrl) {
       trackingUrl = (
         <Button
-          bsSize="small"
+          buttonSize="small"
           onClick={() => query.trackingUrl && window.open(query.trackingUrl)}
         >
           {t('Track Job')}
diff --git a/superset-frontend/src/SqlLab/components/RunQueryActionButton.tsx 
b/superset-frontend/src/SqlLab/components/RunQueryActionButton.tsx
index 7b4fd1e..0dffab4 100644
--- a/superset-frontend/src/SqlLab/components/RunQueryActionButton.tsx
+++ b/superset-frontend/src/SqlLab/components/RunQueryActionButton.tsx
@@ -19,7 +19,7 @@
 import React from 'react';
 import { t } from '@superset-ui/translation';
 
-import Button, { ButtonProps } from '../../components/Button';
+import Button, { ButtonProps } from 'src/components/Button';
 
 const NO_OP = () => undefined;
 
@@ -32,9 +32,6 @@ interface Props {
   stopQuery: () => void;
   sql: string;
 }
-const commonBtnStyle = {
-  width: '140px',
-};
 
 const RunQueryActionButton = ({
   allowAsync = false,
@@ -51,15 +48,14 @@ const RunQueryActionButton = ({
     !!queryState && ['running', 'pending'].indexOf(queryState) > -1;
 
   const commonBtnProps: ButtonProps = {
-    bsSize: 'small',
-    bsStyle: btnStyle,
+    buttonSize: 'small',
+    buttonStyle: btnStyle,
     disabled: !dbId,
-    style: commonBtnStyle,
   };
 
   if (shouldShowStopBtn) {
     return (
-      <Button {...commonBtnProps} onClick={stopQuery}>
+      <Button {...commonBtnProps} cta onClick={stopQuery}>
         <i className="fa fa-stop" /> {t('Stop')}
       </Button>
     );
@@ -67,6 +63,7 @@ const RunQueryActionButton = ({
     return (
       <Button
         {...commonBtnProps}
+        cta
         onClick={() => runQuery(true)}
         key="run-async-btn"
         tooltip={t('Run query asynchronously (Ctrl + ↵)')}
@@ -79,6 +76,7 @@ const RunQueryActionButton = ({
   return (
     <Button
       {...commonBtnProps}
+      cta
       onClick={() => runQuery(false)}
       key="run-btn"
       tooltip={t('Run query synchronously (Ctrl + ↵)')}
diff --git a/superset-frontend/src/SqlLab/components/SaveQuery.jsx 
b/superset-frontend/src/SqlLab/components/SaveQuery.jsx
index b9eb2de..5e7a878 100644
--- a/superset-frontend/src/SqlLab/components/SaveQuery.jsx
+++ b/superset-frontend/src/SqlLab/components/SaveQuery.jsx
@@ -135,7 +135,7 @@ class SaveQuery extends React.PureComponent {
           <Col md={12}>
             {isSaved && (
               <Button
-                bsStyle="primary"
+                buttonStyle="primary"
                 onClick={this.onUpdate}
                 className="m-r-3"
               >
@@ -143,7 +143,7 @@ class SaveQuery extends React.PureComponent {
               </Button>
             )}
             <Button
-              bsStyle={isSaved ? undefined : 'primary'}
+              buttonStyle={isSaved ? undefined : 'primary'}
               onClick={this.onSave}
               className="m-r-3"
             >
@@ -169,7 +169,7 @@ class SaveQuery extends React.PureComponent {
           backdrop="static"
           triggerNode={
             <Button
-              bsSize="small"
+              buttonSize="small"
               className="toggleSave"
               onClick={this.toggleSave}
             >
diff --git a/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx 
b/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
index 08fd388..ed710c0 100644
--- a/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
+++ b/superset-frontend/src/SqlLab/components/ScheduleQueryButton.jsx
@@ -192,7 +192,7 @@ class ScheduleQueryButton extends React.PureComponent {
           modalBody={this.renderModalBody()}
           triggerNode={
             <Button
-              bsSize="small"
+              buttonSize="small"
               className="toggleSchedule"
               onClick={this.toggleSchedule}
               disabled={this.props.disabled}
diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery.jsx 
b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery.jsx
index cb7d133..75291db 100644
--- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery.jsx
+++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery.jsx
@@ -22,7 +22,7 @@ import { Popover, OverlayTrigger } from 'react-bootstrap';
 import { t } from '@superset-ui/translation';
 import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
 
-import Button from '../../components/Button';
+import Button from 'src/components/Button';
 import CopyToClipboard from '../../components/CopyToClipboard';
 import { storeQuery } from '../../utils/common';
 import getClientErrorObject from '../../utils/getClientErrorObject';
@@ -110,7 +110,7 @@ class ShareSqlLabQuery extends React.Component {
         shouldUpdatePosition
         overlay={this.renderPopover()}
       >
-        <Button bsSize="small" className="toggleSave">
+        <Button buttonSize="small" className="toggleSave">
           <i className="fa fa-share" /> {t('Share')}
         </Button>
       </OverlayTrigger>
diff --git a/superset-frontend/src/SqlLab/components/SqlEditor.jsx 
b/superset-frontend/src/SqlLab/components/SqlEditor.jsx
index 976a3be..4f3e72c 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditor.jsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditor.jsx
@@ -398,7 +398,7 @@ class SqlEditor extends React.PureComponent {
             <InputGroup.Button>
               {this.props.database.allow_ctas && (
                 <Button
-                  bsSize="small"
+                  buttonSize="small"
                   disabled={this.state.ctas.length === 0}
                   onClick={this.createTableAs.bind(this)}
                   tooltip={ctasToolTip}
@@ -408,7 +408,7 @@ class SqlEditor extends React.PureComponent {
               )}
               {this.props.database.allow_cvas && (
                 <Button
-                  bsSize="small"
+                  buttonSize="small"
                   disabled={this.state.ctas.length === 0}
                   onClick={this.createViewAs.bind(this)}
                   tooltip={cvasToolTip}
diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx 
b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
index 0f2ac94..6bb7546 100644
--- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
@@ -18,7 +18,7 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 import TableElement from './TableElement';
 import TableSelector from '../../components/TableSelector';
@@ -140,7 +140,11 @@ export default class SqlEditorLeftBar extends 
React.PureComponent {
           </div>
         </div>
         {shouldShowReset && (
-          <Button bsSize="small" bsStyle="danger" onClick={this.resetState}>
+          <Button
+            buttonSize="small"
+            buttonStyle="danger"
+            onClick={this.resetState}
+          >
             <i className="fa fa-bomb" /> {t('Reset State')}
           </Button>
         )}
diff --git a/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx 
b/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
index 7127cc3..15f6572 100644
--- a/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
+++ b/superset-frontend/src/SqlLab/components/TemplateParamsEditor.jsx
@@ -29,8 +29,8 @@ import 'brace/theme/textmate';
 import { t } from '@superset-ui/translation';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
 
+import Button from 'src/components/Button';
 import ModalTrigger from '../../components/ModalTrigger';
-import Button from '../../components/Button';
 
 const propTypes = {
   onChange: PropTypes.func,
diff --git a/superset-frontend/src/addSlice/AddSliceContainer.tsx 
b/superset-frontend/src/addSlice/AddSliceContainer.tsx
index fbcd3b3..436397d 100644
--- a/superset-frontend/src/addSlice/AddSliceContainer.tsx
+++ b/superset-frontend/src/addSlice/AddSliceContainer.tsx
@@ -17,7 +17,8 @@
  * under the License.
  */
 import React from 'react';
-import { Button, Panel } from 'react-bootstrap';
+import { Panel } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Select from 'src/components/Select';
 import { t } from '@superset-ui/translation';
 
@@ -142,7 +143,7 @@ export default class AddSliceContainer extends 
React.PureComponent<
             <br />
             <hr />
             <Button
-              bsStyle="primary"
+              buttonStyle="primary"
               disabled={this.isBtnDisabled()}
               onClick={this.gotoSlice}
             >
diff --git a/superset-frontend/src/common/components/Modal.tsx 
b/superset-frontend/src/common/components/Modal.tsx
index ab29c9f..9757315 100644
--- a/superset-frontend/src/common/components/Modal.tsx
+++ b/superset-frontend/src/common/components/Modal.tsx
@@ -20,7 +20,7 @@ import React from 'react';
 import styled from '@superset-ui/style';
 import { Modal as BaseModal } from 'src/common/components';
 import { t } from '@superset-ui/translation';
-import Button from 'src/views/CRUD/data/dataset/Button';
+import Button from 'src/components/Button';
 
 interface ModalProps {
   className?: string;
diff --git a/superset-frontend/src/components/Button/button.stories.jsx 
b/superset-frontend/src/components/Button/Button.stories.jsx
similarity index 74%
rename from superset-frontend/src/components/Button/button.stories.jsx
rename to superset-frontend/src/components/Button/Button.stories.jsx
index d93474c..3c578e8 100644
--- a/superset-frontend/src/components/Button/button.stories.jsx
+++ b/superset-frontend/src/components/Button/Button.stories.jsx
@@ -25,13 +25,16 @@ export default {
   title: 'Button',
   component: Button,
   decorators: [withKnobs],
+  excludeStories: /.*Knob$/,
 };
 
-const bsStyleKnob = {
+export const buttonStyleKnob = {
   label: 'Types',
   options: {
     Primary: 'primary',
     Secondary: 'secondary',
+    Tertiary: 'tertiary',
+    Dashed: 'dashed',
     Danger: 'danger',
     Warning: 'warning',
     Success: 'success',
@@ -42,17 +45,18 @@ const bsStyleKnob = {
   defaultValue: null,
   // groupId: 'ButtonType',
 };
-const bsSizeKnob = {
+
+export const buttonSizeKnob = {
   label: 'Sizes',
   options: {
     XS: 'xsmall',
     S: 'small',
-    M: 'medium',
+    Default: null,
     L: 'large',
-    None: null,
   },
   defaultValue: null,
 };
+
 // TODO remove the use of these in the codebase where they're not necessary
 // const classKnob = {
 //   label: 'Known Classes',
@@ -62,7 +66,6 @@ const bsSizeKnob = {
 //     Reset: 'reset',
 //     Fetch: 'fetch',
 //     Query: 'query',
-//     saveBtn: 'save-btn',
 //     MR3: 'm-r-3',
 //     cancelQuery: 'cancelQuery',
 //     toggleSave: 'toggleSave',
@@ -101,43 +104,43 @@ const hrefKnob = {
 
 export const ButtonGallery = () => (
   <>
-    {Object.values(bsSizeKnob.options)
-      .filter(a => a)
-      .map(size => (
-        <div>
-          <h4>{size}</h4>
-          {Object.values(bsStyleKnob.options)
-            .filter(o => o)
-            .map(style => (
-              <Button
-                disabled={boolean('Disabled', false)}
-                bsStyle={style}
-                bsSize={size}
-                onClick={action('clicked')}
-                style={{ marginRight: 5 }}
-              >
-                {style}
-              </Button>
-            ))}
-        </div>
-      ))}
+    {Object.entries(buttonSizeKnob.options).map(([name, size]) => (
+      <div key={size}>
+        <h4>{name}</h4>
+        {Object.values(buttonStyleKnob.options)
+          .filter(o => o)
+          .map(style => (
+            <Button
+              disabled={boolean('Disabled', false)}
+              cta={boolean('CTA', false)}
+              buttonStyle={style}
+              buttonSize={size}
+              onClick={action('clicked')}
+              key={`${style}_${size}`}
+            >
+              {style}
+            </Button>
+          ))}
+      </div>
+    ))}
   </>
 );
 
 export const InteractiveButton = () => (
   <Button
     disabled={boolean('Disabled', false)}
-    bsStyle={select(
-      bsStyleKnob.label,
-      bsStyleKnob.options,
-      bsStyleKnob.defaultValue,
-      bsStyleKnob.groupId,
+    cta={boolean('CTA', false)}
+    buttonStyle={select(
+      buttonStyleKnob.label,
+      buttonStyleKnob.options,
+      buttonStyleKnob.defaultValue,
+      buttonStyleKnob.groupId,
     )}
-    bsSize={select(
-      bsSizeKnob.label,
-      bsSizeKnob.options,
-      bsSizeKnob.defaultValue,
-      bsSizeKnob.groupId,
+    size={select(
+      buttonSizeKnob.label,
+      buttonSizeKnob.options,
+      buttonSizeKnob.defaultValue,
+      buttonSizeKnob.groupId,
     )}
     onClick={action('clicked')}
     type={select(
diff --git a/superset-frontend/src/components/Button/Button.test.tsx 
b/superset-frontend/src/components/Button/Button.test.tsx
new file mode 100644
index 0000000..611a7db
--- /dev/null
+++ b/superset-frontend/src/components/Button/Button.test.tsx
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { ReactWrapper } from 'enzyme';
+import { styledMount as mount } from 'spec/helpers/theming';
+import Button from '.';
+import {
+  ButtonGallery,
+  buttonSizeKnob,
+  buttonStyleKnob,
+} from './Button.stories';
+
+describe('Button', () => {
+  let wrapper: ReactWrapper;
+
+  // test the basic component
+  it('renders the base component', () => {
+    expect(React.isValidElement(<Button />)).toBe(true);
+  });
+
+  it('works with an onClick handler', () => {
+    const mockAction = jest.fn();
+    wrapper = mount(<Button onClick={mockAction} />);
+    wrapper.find('Button').first().simulate('click');
+    expect(mockAction).toHaveBeenCalled();
+  });
+
+  it('does not handle onClicks when disabled', () => {
+    const mockAction = jest.fn();
+    wrapper = mount(<Button onClick={mockAction} disabled />);
+    wrapper.find('Button').first().simulate('click');
+    expect(mockAction).toHaveBeenCalledTimes(0);
+  });
+
+  // test stories from the storybook!
+  it('All the sorybook gallery variants mount', () => {
+    wrapper = mount(<ButtonGallery />);
+
+    const permutationCount =
+      Object.values(buttonStyleKnob.options).filter(o => o).length *
+      Object.values(buttonSizeKnob.options).length;
+
+    expect(wrapper.find(Button).length).toEqual(permutationCount);
+  });
+
+  // test things NOT in the storybook!
+  it('renders custom button styles without melting', () => {
+    wrapper = mount(<Button buttonStyle="foobar" />);
+    expect(wrapper.find('Button.btn-foobar')).toHaveLength(1);
+  });
+});
diff --git a/superset-frontend/src/components/Button/index.tsx 
b/superset-frontend/src/components/Button/index.tsx
index a885431..d40d3f9 100644
--- a/superset-frontend/src/components/Button/index.tsx
+++ b/superset-frontend/src/components/Button/index.tsx
@@ -18,6 +18,8 @@
  */
 import React from 'react';
 import { kebabCase } from 'lodash';
+import { mix } from 'polished';
+import cx from 'classnames';
 import {
   Button as BootstrapButton,
   Tooltip,
@@ -40,52 +42,201 @@ export interface ButtonProps {
   placement?: string;
   onClick?: OnClickHandler;
   disabled?: boolean;
-  bsStyle?: string;
+  buttonStyle?: string;
   btnStyles?: string;
-  bsSize?: BootstrapButton.ButtonProps['bsSize'];
+  buttonSize?: BootstrapButton.ButtonProps['bsSize'];
   style?: BootstrapButton.ButtonProps['style'];
   children?: React.ReactNode;
   dropdownItems?: DropdownItemProps[];
+  href?: string; // React-Bootstrap creates a link when this is passed in.
+  target?: string; // React-Bootstrap creates a link when this is passed in.
+  type?: string; // React-Bootstrap supports this when rendering an HTML 
button element
+  cta?: boolean;
 }
 
 const BUTTON_WRAPPER_STYLE = { display: 'inline-block', cursor: 'not-allowed' 
};
 
 const SupersetButton = styled(BootstrapButton)`
-  &.supersetButton {
-    border-radius: ${({ theme }) => theme.borderRadius}px;
-    border: none;
-    color: ${({ theme }) => theme.colors.secondary.light5};
-    font-size: ${({ theme }) => theme.typography.sizes.s}px;
-    font-weight: ${({ theme }) => theme.typography.weights.bold};
-    min-width: ${({ theme }) => theme.gridUnit * 36}px;
-    min-height: ${({ theme }) => theme.gridUnit * 8}px;
-    text-transform: uppercase;
-    margin-left: ${({ theme }) => theme.gridUnit * 4}px;
-    &:first-of-type {
-      margin-left: 0;
-    }
+  &:focus,
+  &:active,
+  &:focus:active {
+    outline: none;
+    box-shadow: none;
+  }
+  transition: all ${({ theme }) => theme.transitionTiming}s;
+  border-radius: ${({ theme }) => theme.borderRadius}px;
+  border: none;
+  font-size: ${({ theme }) => theme.typography.sizes.s}px;
+  font-weight: ${({ theme }) => theme.typography.weights.bold};
+  margin-left: ${({ theme }) => theme.gridUnit * 4}px;
+  &:first-of-type {
+    margin-left: 0;
+  }
 
-    i {
-      padding: 0 ${({ theme }) => theme.gridUnit * 2}px 0 0;
-    }
+  i {
+    padding: 0 ${({ theme }) => theme.gridUnit * 2}px 0 0;
+  }
 
-    &.primary {
-      background-color: ${({ theme }) => theme.colors.primary.base};
+  /* SIP 34 colors! */
+  &.btn {
+    border: 1px solid transparent; /* this just makes sure the height is the 
same as tertiary/dashed buttons */
+    &:hover,
+    &:active {
+      border: 1px solid transparent;
     }
-    &.secondary {
-      color: ${({ theme }) => theme.colors.primary.base};
+    &-default,
+    &-secondary {
       background-color: ${({ theme }) => theme.colors.primary.light4};
+      color: ${({ theme }) => theme.colors.primary.dark1};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, 
theme.colors.primary.light4)};
+        color: ${({ theme }) => theme.colors.primary.dark1};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.25, theme.colors.primary.base, theme.colors.primary.light4)};
+        color: ${({ theme }) => theme.colors.primary.dark1};
+      }
+    }
+    &-tertiary,
+    &-dashed {
+      border-width: 1px;
+      border-style: solid;
+      background-color: ${({ theme }) => theme.colors.grayscale.light5};
+      color: ${({ theme }) => theme.colors.primary.dark1};
+      border-color: ${({ theme }) => theme.colors.primary.dark1};
+      &:hover {
+        background-color: ${({ theme }) => theme.colors.grayscale.light5};
+        color: ${({ theme }) => theme.colors.primary.dark1};
+        border-color: ${({ theme }) => theme.colors.primary.light1};
+      }
+      &:active {
+        background-color: ${({ theme }) => theme.colors.grayscale.light5};
+        color: ${({ theme }) => theme.colors.primary.dark1};
+        border-color: ${({ theme }) => theme.colors.primary.dark1};
+      }
+      &[disabled],
+      &[disabled]:hover {
+        background-color: ${({ theme }) => theme.colors.grayscale.light5};
+        color: ${({ theme }) => theme.colors.grayscale.base};
+        border-color: ${({ theme }) => theme.colors.grayscale.light2};
+      }
+    }
+    &-dashed {
+      border-style: dashed;
+      &:hover,
+      &:active {
+        border-style: dashed;
+      }
     }
-    &.danger {
+    &-link {
+      background: none;
+      text-decoration: none;
+      color: ${({ theme }) => theme.colors.primary.dark1};
+      &:hover {
+        background: none;
+        color: ${({ theme }) => theme.colors.primary.base};
+      }
+      &:active {
+        background: none;
+        color: ${({ theme }) => theme.colors.primary.dark1};
+      }
+      &[disabled],
+      &[disabled]:hover {
+        background: none;
+        color: ${({ theme }) => theme.colors.grayscale.base};
+      }
+    }
+    &-primary {
+      background-color: ${({ theme }) => theme.colors.primary.dark1};
+      color: ${({ theme }) => theme.colors.grayscale.light5};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, theme.colors.primary.dark1)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.2, theme.colors.grayscale.dark2, theme.colors.primary.dark1)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+    }
+    &-danger {
       background-color: ${({ theme }) => theme.colors.error.base};
+      color: ${({ theme }) => theme.colors.grayscale.light5};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, theme.colors.error.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.2, theme.colors.grayscale.dark2, theme.colors.error.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+    }
+    &-success {
+      background-color: ${({ theme }) => theme.colors.success.base};
+      color: ${({ theme }) => theme.colors.grayscale.light5};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, theme.colors.success.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.2, theme.colors.grayscale.dark2, theme.colors.success.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
     }
+    &-warning {
+      background-color: ${({ theme }) => theme.colors.warning.base};
+      color: ${({ theme }) => theme.colors.grayscale.light5};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, theme.colors.warning.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.2, theme.colors.grayscale.dark2, theme.colors.warning.base)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+    }
+    &-info {
+      background-color: ${({ theme }) => theme.colors.info.dark1};
+      color: ${({ theme }) => theme.colors.grayscale.light5};
+      &:hover {
+        background-color: ${({ theme }) =>
+          mix(0.1, theme.colors.grayscale.light5, theme.colors.info.dark1)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+      &:active {
+        background-color: ${({ theme }) =>
+          mix(0.2, theme.colors.grayscale.dark2, theme.colors.info.dark1)};
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+      }
+    }
+    &[disabled],
+    &[disabled]:hover {
+      background-color: ${({ theme }) => theme.colors.grayscale.light2};
+      color: ${({ theme }) => theme.colors.grayscale.light1};
+    }
+  }
+
+  /* big Call to Action buttons */
+  &.cta {
+    min-width: ${({ theme }) => theme.gridUnit * 36}px;
+    min-height: ${({ theme }) => theme.gridUnit * 8}px;
+    text-transform: uppercase;
   }
 `;
 
 export default function Button(props: ButtonProps) {
   const buttonProps = {
     ...props,
-    bsSize: props.bsSize || 'sm',
+    bsSize: props.buttonSize,
     placement: props.placement || 'top',
   };
   const tooltip = props.tooltip;
@@ -100,17 +251,40 @@ export default function Button(props: ButtonProps) {
     buttonProps.style = { pointerEvents: 'none' };
   }
 
+  const officialBootstrapStyles = [
+    'success',
+    'warning',
+    'danger',
+    'info',
+    'default',
+    'primary',
+  ];
+
+  const transformedProps = {
+    ...buttonProps,
+    bsStyle: officialBootstrapStyles.includes(props.buttonStyle || '')
+      ? props.buttonStyle
+      : 'default',
+    className: cx(props.className, {
+      cta: !!buttonProps.cta,
+      [`btn-${props.buttonStyle}`]: !officialBootstrapStyles.includes(
+        props.buttonStyle || '',
+      ),
+    }),
+  };
+  delete transformedProps.dropdownItems;
+  delete transformedProps.buttonSize;
+  delete transformedProps.buttonStyle;
+  delete transformedProps.cta;
+
   let button = (
-    <SupersetButton {...buttonProps}>{props.children}</SupersetButton>
+    <SupersetButton {...transformedProps}>{props.children}</SupersetButton>
   );
 
-  const whittledProps = { ...buttonProps };
-  delete whittledProps.dropdownItems;
-
   if (dropdownItems) {
     button = (
       <div style={BUTTON_WRAPPER_STYLE}>
-        <SupersetButton {...whittledProps} data-toggle="dropdown">
+        <SupersetButton {...transformedProps} data-toggle="dropdown">
           {props.children}
         </SupersetButton>
         <ul className="dropdown-menu">
diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx 
b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
index b176457..2b569ad 100644
--- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
@@ -21,7 +21,7 @@ import { Modal } from 'react-bootstrap';
 import { styled, supersetTheme } from '@superset-ui/style';
 import { t } from '@superset-ui/translation';
 import { noOp } from 'src/utils/common';
-import Button from 'src/views/CRUD/data/dataset/Button';
+import Button from 'src/components/Button';
 
 import Icon from '../Icon';
 import { ErrorLevel, ErrorSource } from './types';
@@ -190,7 +190,11 @@ export default function ErrorAlert({
                 copyNode={<Button onClick={noOp}>{t('Copy Message')}</Button>}
               />
             )}
-            <Button bsStyle="primary" onClick={() => setIsModalOpen(false)}>
+            <Button
+              cta
+              buttonStyle="primary"
+              onClick={() => setIsModalOpen(false)}
+            >
               {t('Close')}
             </Button>
           </Modal.Footer>
diff --git a/superset-frontend/src/components/ExpandableList.tsx 
b/superset-frontend/src/components/ExpandableList.tsx
index f827c98..20d980e 100644
--- a/superset-frontend/src/components/ExpandableList.tsx
+++ b/superset-frontend/src/components/ExpandableList.tsx
@@ -39,12 +39,12 @@ export default function ExpandableList({ items, display = 3 
}: Props) {
   const showMoreAction = items.length > display;
 
   const lessAction = (
-    <Button bsStyle="link" bsSize="xsmall" onClick={toggleShowingAll}>
+    <Button buttonStyle="link" buttonSize="xsmall" onClick={toggleShowingAll}>
       less
     </Button>
   );
   const moreAction = (
-    <Button bsStyle="link" bsSize="xsmall" onClick={toggleShowingAll}>
+    <Button buttonStyle="link" buttonSize="xsmall" onClick={toggleShowingAll}>
       {items.length - itemsToDisplay.length} more
     </Button>
   );
diff --git a/superset-frontend/src/components/Label/Label.stories.tsx 
b/superset-frontend/src/components/Label/Label.stories.tsx
index 143e2c8..89b36e2 100644
--- a/superset-frontend/src/components/Label/Label.stories.tsx
+++ b/superset-frontend/src/components/Label/Label.stories.tsx
@@ -25,7 +25,7 @@ export default {
   title: 'Label',
   component: Label,
   decorators: [withKnobs],
-  excludeStories: ['bsStyleKnob'],
+  excludeStories: /.*Knob$/,
 };
 
 export const bsStyleKnob = {
diff --git a/superset-frontend/src/components/ListView/ListView.tsx 
b/superset-frontend/src/components/ListView/ListView.tsx
index f825753..54fdeae 100644
--- a/superset-frontend/src/components/ListView/ListView.tsx
+++ b/superset-frontend/src/components/ListView/ListView.tsx
@@ -311,11 +311,12 @@ function ListView<T extends object = any>({
                     <Button
                       data-test="bulk-select-action"
                       key={action.key}
-                      className={cx('supersetButton', {
+                      className={cx({
                         danger: action.type === 'danger',
                         primary: action.type === 'primary',
                         secondary: action.type === 'secondary',
                       })}
+                      cta
                       onClick={() =>
                         action.onSelect(selectedFlatRows.map(r => r.original))
                       }
diff --git a/superset-frontend/src/components/Menu/Menu.tsx 
b/superset-frontend/src/components/Menu/Menu.tsx
index 23da030..ef01b35 100644
--- a/superset-frontend/src/components/Menu/Menu.tsx
+++ b/superset-frontend/src/components/Menu/Menu.tsx
@@ -129,6 +129,14 @@ const StyledHeader = styled.header`
     margin-bottom: 8px;
     border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
   }
+  .navbar-right {
+    display: flex;
+    align-items: center;
+    .dropdown:first-of-type {
+      /* this is the "+ NEW" button. Sweep this up when it's replaced */
+      margin-right: ${({ theme }) => theme.gridUnit * 2}px;
+    }
+  }
 `;
 
 export function Menu({
diff --git a/superset-frontend/src/components/Menu/NewMenu.tsx 
b/superset-frontend/src/components/Menu/NewMenu.tsx
index 055ca2e..5ac1fd2 100644
--- a/superset-frontend/src/components/Menu/NewMenu.tsx
+++ b/superset-frontend/src/components/Menu/NewMenu.tsx
@@ -17,15 +17,9 @@
  * under the License.
  */
 import React from 'react';
-import styled from '@superset-ui/style';
 import { t } from '@superset-ui/translation';
 import Button, { DropdownItemProps } from '../Button';
 
-const StyledButton = styled(Button)`
-  margin-top: 12px;
-  margin-right: 30px;
-`;
-
 const dropdownItems: DropdownItemProps[] = [
   {
     label: t('SQL Query'),
@@ -47,12 +41,9 @@ const dropdownItems: DropdownItemProps[] = [
 export default function NewMenu() {
   return (
     <li className="dropdown">
-      <StyledButton
-        className="dropdown-toggle btn btn-sm btn-primary"
-        dropdownItems={dropdownItems}
-      >
+      <Button buttonStyle="primary" dropdownItems={dropdownItems}>
         <i className="fa fa-plus" /> New
-      </StyledButton>
+      </Button>
     </li>
   );
 }
diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx 
b/superset-frontend/src/components/Menu/SubMenu.tsx
index f3a27e9..1450001 100644
--- a/superset-frontend/src/components/Menu/SubMenu.tsx
+++ b/superset-frontend/src/components/Menu/SubMenu.tsx
@@ -26,12 +26,8 @@ const StyledHeader = styled.header`
     font-weight: ${({ theme }) => theme.typography.weights.bold};
   }
   .navbar-right {
-    .supersetButton {
-      margin: ${({ theme }) =>
-        `${theme.gridUnit * 2}px ${theme.gridUnit * 4}px ${
-          theme.gridUnit * 2
-        }px 0`};
-    }
+    padding: 8px 0;
+    margin-right: 0;
   }
   .navbar-nav {
     li {
@@ -94,16 +90,18 @@ const SubMenu: React.FunctionComponent<SubMenuProps> = 
props => {
         <Nav className="navbar-right">
           {props.secondaryButton && (
             <Button
-              className="supersetButton secondary"
+              buttonStyle="secondary"
               onClick={props.secondaryButton.onClick}
+              cta
             >
               {props.secondaryButton.name}
             </Button>
           )}
           {props.primaryButton && (
             <Button
-              className="supersetButton primary"
+              buttonStyle="primary"
               onClick={props.primaryButton.onClick}
+              cta
             >
               {props.primaryButton.name}
             </Button>
diff --git a/superset-frontend/src/components/Modal.tsx 
b/superset-frontend/src/components/Modal.tsx
index eed1215..0c179bb 100644
--- a/superset-frontend/src/components/Modal.tsx
+++ b/superset-frontend/src/components/Modal.tsx
@@ -20,7 +20,7 @@ import React from 'react';
 import styled from '@superset-ui/style';
 import { Modal as BaseModal } from 'react-bootstrap';
 import { t } from '@superset-ui/translation';
-import Button from 'src/views/CRUD/data/dataset/Button';
+import Button from 'src/components/Button';
 
 interface ModalProps {
   children: React.ReactNode;
@@ -54,9 +54,6 @@ const StyledModal = styled(BaseModal)`
   .modal-footer {
     border-top: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
     padding: 16px;
-    .btn + .btn {
-      margin-left: 8px;
-    }
   }
 `;
 
@@ -86,11 +83,14 @@ export default function Modal({
       <BaseModal.Body>{children}</BaseModal.Body>
       <BaseModal.Footer>
         <span className="float-right">
-          <Button onClick={onHide}>{t('Cancel')}</Button>
+          <Button onClick={onHide} cta>
+            {t('Cancel')}
+          </Button>
           <Button
-            bsStyle={primaryButtonType}
+            buttonStyle={primaryButtonType}
             disabled={disablePrimaryButton}
             onClick={onHandledPrimaryAction}
+            cta
           >
             {primaryButtonName}
           </Button>
diff --git a/superset-frontend/src/components/ModalTrigger.jsx 
b/superset-frontend/src/components/ModalTrigger.jsx
index 1a7ddd1..ea93080 100644
--- a/superset-frontend/src/components/ModalTrigger.jsx
+++ b/superset-frontend/src/components/ModalTrigger.jsx
@@ -19,9 +19,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Modal, MenuItem } from 'react-bootstrap';
-import cx from 'classnames';
 
-import Button from './Button';
+import Button from 'src/components/Button';
 
 const propTypes = {
   dialogClassName: PropTypes.string,
@@ -96,9 +95,6 @@ export default class ModalTrigger extends React.Component {
   }
 
   render() {
-    const classNames = cx({
-      'btn btn-default btn-sm': this.props.isButton,
-    });
     if (this.props.isButton) {
       return (
         <>
@@ -123,7 +119,7 @@ export default class ModalTrigger extends React.Component {
     /* eslint-disable jsx-a11y/interactive-supports-focus */
     return (
       <>
-        <span className={classNames} onClick={this.open} role="button">
+        <span onClick={this.open} role="button">
           {this.props.triggerNode}
         </span>
         {this.renderModal()}
diff --git a/superset-frontend/src/components/RefreshChartOverlay.tsx 
b/superset-frontend/src/components/RefreshChartOverlay.tsx
index 75cce63..26a0994 100644
--- a/superset-frontend/src/components/RefreshChartOverlay.tsx
+++ b/superset-frontend/src/components/RefreshChartOverlay.tsx
@@ -53,7 +53,7 @@ class RefreshChartOverlay extends React.PureComponent<Props> {
           <Button
             className="refresh-btn"
             onClick={this.props.onQuery}
-            bsStyle="primary"
+            buttonStyle="primary"
           >
             {t('Run Query')}
           </Button>
diff --git 
a/superset-frontend/src/dashboard/components/DeleteComponentModal.jsx 
b/superset-frontend/src/dashboard/components/DeleteComponentModal.jsx
index 1d50017..5efcb79 100644
--- a/superset-frontend/src/dashboard/components/DeleteComponentModal.jsx
+++ b/superset-frontend/src/dashboard/components/DeleteComponentModal.jsx
@@ -18,7 +18,7 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 
 import ModalTrigger from '../../components/ModalTrigger';
@@ -66,7 +66,7 @@ export default class DeleteComponentModal extends 
React.PureComponent {
             </div>
             <div className="dashboard-modal-actions-container">
               <Button onClick={this.close}>{t('Cancel')}</Button>
-              <Button bsStyle="primary" onClick={this.deleteTab}>
+              <Button buttonStyle="primary" onClick={this.deleteTab}>
                 {t('Delete')}
               </Button>
             </div>
diff --git a/superset-frontend/src/dashboard/components/Header.jsx 
b/superset-frontend/src/dashboard/components/Header.jsx
index 89f2084..fa418b4 100644
--- a/superset-frontend/src/dashboard/components/Header.jsx
+++ b/superset-frontend/src/dashboard/components/Header.jsx
@@ -26,10 +26,10 @@ import { CategoricalColorNamespace } from 
'@superset-ui/color';
 import { t } from '@superset-ui/translation';
 
 import Icon from 'src/components/Icon';
+import Button from 'src/components/Button';
 
 import HeaderActionsDropdown from './HeaderActionsDropdown';
 import EditableTitle from '../../components/EditableTitle';
-import Button from '../../components/Button';
 import FaveStar from '../../components/FaveStar';
 import PublishedStatus from './PublishedStatus';
 import UndoRedoKeylisteners from './UndoRedoKeylisteners';
@@ -390,36 +390,40 @@ class Header extends React.PureComponent {
                 <>
                   <ButtonGroup className="m-r-5">
                     <Button
-                      bsSize="small"
+                      buttonSize="small"
                       onClick={onUndo}
                       disabled={undoLength < 1}
-                      bsStyle={this.state.emphasizeUndo ? 'primary' : 
undefined}
+                      buttonStyle={
+                        this.state.emphasizeUndo ? 'primary' : undefined
+                      }
                     >
                       <i title="Undo" className="undo-action fa fa-reply" />
                       &nbsp;
                     </Button>
                     <Button
-                      bsSize="small"
+                      buttonSize="small"
                       onClick={onRedo}
                       disabled={redoLength < 1}
-                      bsStyle={this.state.emphasizeRedo ? 'primary' : 
undefined}
+                      buttonStyle={
+                        this.state.emphasizeRedo ? 'primary' : undefined
+                      }
                     >
                       &nbsp;
                       <i title="Redo" className="redo-action fa fa-share" />
                     </Button>
                   </ButtonGroup>
                   <Button
-                    bsSize="small"
+                    buttonSize="small"
                     className="m-r-5"
                     onClick={this.constructor.discardChanges}
-                    bsStyle="default"
+                    buttonStyle="default"
                   >
                     {t('Discard Changes')}
                   </Button>
                   <Button
-                    bsSize="small"
+                    buttonSize="small"
                     disabled={!hasUnsavedChanges}
-                    bsStyle="primary"
+                    buttonStyle="primary"
                     onClick={this.overwriteDashboard}
                   >
                     {t('Save')}
diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx 
b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
index aac3be2..9f7fd2f 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
@@ -18,7 +18,8 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Row, Col, Button, Modal, FormControl } from 'react-bootstrap';
+import { Row, Col, Modal, FormControl } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Dialog from 'react-bootstrap-dialog';
 import { AsyncSelect } from 'src/components/Select';
 import AceEditor from 'react-ace';
@@ -288,11 +289,7 @@ class PropertiesModal extends React.PureComponent {
             <Row>
               <Col md={12}>
                 <h3 style={{ marginTop: '1em' }}>
-                  <button
-                    type="button"
-                    className="text-button"
-                    onClick={this.toggleAdvanced}
-                  >
+                  <Button buttonStyle="link" onClick={this.toggleAdvanced}>
                     <i
                       className={`fa fa-angle-${
                         isAdvancedOpen ? 'down' : 'right'
@@ -300,7 +297,7 @@ class PropertiesModal extends React.PureComponent {
                       style={{ minWidth: '1em' }}
                     />
                     {t('Advanced')}
-                  </button>
+                  </Button>
                 </h3>
                 {isAdvancedOpen && (
                   <>
@@ -332,14 +329,15 @@ class PropertiesModal extends React.PureComponent {
             <span className="float-right">
               <Button
                 type="submit"
-                bsSize="sm"
-                bsStyle="primary"
+                buttonSize="sm"
+                buttonStyle="primary"
                 className="m-r-5"
                 disabled={errors.length > 0}
+                cta
               >
                 {saveLabel}
               </Button>
-              <Button type="button" bsSize="sm" onClick={onHide}>
+              <Button type="button" buttonSize="sm" onClick={onHide} cta>
                 {t('Cancel')}
               </Button>
               <Dialog
diff --git a/superset-frontend/src/dashboard/components/PublishedStatus.jsx 
b/superset-frontend/src/dashboard/components/PublishedStatus.jsx
index cbf86d9..2bff312 100644
--- a/superset-frontend/src/dashboard/components/PublishedStatus.jsx
+++ b/superset-frontend/src/dashboard/components/PublishedStatus.jsx
@@ -19,7 +19,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { t } from '@superset-ui/translation';
-import TooltipWrapper from '../../components/TooltipWrapper';
+import TooltipWrapper from 'src/components/TooltipWrapper';
+import Label from 'src/components/Label';
 
 const propTypes = {
   dashboardId: PropTypes.number.isRequired,
@@ -43,14 +44,6 @@ const publishedTooltip = t(
   'This dashboard is published. Click to make it a draft.',
 );
 
-const divStyle = {
-  border: '1px dotted black',
-  backgroundColor: '#F9F9F9',
-  padding: '3px 7px 3px 7px',
-  fontFamily: 'Monospace',
-  fontSize: '16px',
-};
-
 export default class PublishedStatus extends React.Component {
   componentDidMount() {
     this.togglePublished = this.togglePublished.bind(this);
@@ -71,14 +64,13 @@ export default class PublishedStatus extends 
React.Component {
             placement="bottom"
             tooltip={draftButtonTooltip}
           >
-            <button
-              style={divStyle}
+            <Label
               onClick={() => {
                 this.togglePublished();
               }}
             >
               Draft
-            </button>
+            </Label>
           </TooltipWrapper>
         );
       }
@@ -88,7 +80,7 @@ export default class PublishedStatus extends React.Component {
           placement="bottom"
           tooltip={draftDivTooltip}
         >
-          <div style={divStyle}>Draft</div>
+          <Label>Draft</Label>
         </TooltipWrapper>
       );
     }
@@ -101,14 +93,13 @@ export default class PublishedStatus extends 
React.Component {
           placement="bottom"
           tooltip={publishedTooltip}
         >
-          <button
-            style={divStyle}
+          <Label
             onClick={() => {
               this.togglePublished();
             }}
           >
             Published
-          </button>
+          </Label>
         </TooltipWrapper>
       );
     }
diff --git 
a/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx 
b/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
index c6957a3..7a00147 100644
--- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
+++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
@@ -20,7 +20,8 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import Select from 'src/components/Select';
 import { t } from '@superset-ui/translation';
-import { Alert, Button } from 'react-bootstrap';
+import { Alert } from 'react-bootstrap';
+import Button from 'src/components/Button';
 
 import ModalTrigger from 'src/components/ModalTrigger';
 import FormLabel from 'src/components/FormLabel';
@@ -116,10 +117,10 @@ class RefreshIntervalModal extends React.PureComponent {
         }
         modalFooter={
           <>
-            <Button bsStyle="primary" bsSize="sm" onClick={this.onSave}>
+            <Button buttonStyle="primary" buttonSize="sm" 
onClick={this.onSave}>
               {editMode ? t('Save') : t('Save for this session')}
             </Button>
-            <Button onClick={this.onCancel} bsSize="sm">
+            <Button onClick={this.onCancel} buttonSize="sm">
               {t('Cancel')}
             </Button>
           </>
diff --git a/superset-frontend/src/dashboard/components/SaveModal.jsx 
b/superset-frontend/src/dashboard/components/SaveModal.jsx
index 16a5d1e..7e8b87b 100644
--- a/superset-frontend/src/dashboard/components/SaveModal.jsx
+++ b/superset-frontend/src/dashboard/components/SaveModal.jsx
@@ -19,7 +19,8 @@
 /* eslint-env browser */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button, FormControl, FormGroup, Radio } from 'react-bootstrap';
+import { FormControl, FormGroup, Radio } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { CategoricalColorNamespace } from '@superset-ui/color';
 import { t } from '@superset-ui/translation';
 
@@ -191,7 +192,7 @@ class SaveModal extends React.PureComponent {
         }
         modalFooter={
           <div>
-            <Button bsStyle="primary" onClick={this.saveDashboard}>
+            <Button buttonStyle="primary" onClick={this.saveDashboard}>
               {t('Save')}
             </Button>
           </div>
diff --git 
a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
 
b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
index e3edd2b..204eb20 100644
--- 
a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
+++ 
b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
@@ -19,7 +19,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import cx from 'classnames';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 
 import buildFilterScopeTreeEntry from '../../util/buildFilterScopeTreeEntry';
@@ -513,11 +513,11 @@ export default class FilterScopeSelector extends 
React.PureComponent {
         </div>
 
         <div className="dashboard-modal-actions-container">
-          <Button bsSize="sm" onClick={this.onClose}>
+          <Button buttonSize="sm" onClick={this.onClose}>
             {t('Close')}
           </Button>
           {showSelector && (
-            <Button bsSize="sm" bsStyle="primary" onClick={this.onSave}>
+            <Button buttonSize="sm" buttonStyle="primary" 
onClick={this.onSave}>
               {t('Save')}
             </Button>
           )}
diff --git a/superset-frontend/src/dashboard/stylesheets/buttons.less 
b/superset-frontend/src/dashboard/stylesheets/buttons.less
index f3527f7..9cec645 100644
--- a/superset-frontend/src/dashboard/stylesheets/buttons.less
+++ b/superset-frontend/src/dashboard/stylesheets/buttons.less
@@ -41,14 +41,3 @@
   padding-left: 8px;
   font-size: @font-size-m;
 }
-
-.text-button {
-  outline: none;
-  border: none;
-  margin: 0;
-  padding: 0;
-  background: none;
-  text-decoration: none;
-  font-size: inherit;
-  font-weight: inherit;
-}
diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx 
b/superset-frontend/src/datasource/DatasourceEditor.jsx
index 9f3d110..4a36b90 100644
--- a/superset-frontend/src/datasource/DatasourceEditor.jsx
+++ b/superset-frontend/src/datasource/DatasourceEditor.jsx
@@ -784,7 +784,7 @@ export class DatasourceEditor extends React.PureComponent {
                   }
                 />
                 <Button
-                  bsStyle="primary"
+                  buttonStyle="primary"
                   onClick={this.syncMetadata}
                   className="sync-from-source"
                   disabled={!!datasource.sql}
diff --git a/superset-frontend/src/datasource/DatasourceModal.tsx 
b/superset-frontend/src/datasource/DatasourceModal.tsx
index eb33a32..6af23b6 100644
--- a/superset-frontend/src/datasource/DatasourceModal.tsx
+++ b/superset-frontend/src/datasource/DatasourceModal.tsx
@@ -17,7 +17,8 @@
  * under the License.
  */
 import React, { FunctionComponent, useState, useRef } from 'react';
-import { Alert, Button, Modal } from 'react-bootstrap';
+import { Alert, Modal } from 'react-bootstrap';
+import Button from 'src/components/Button';
 // @ts-ignore
 import Dialog from 'react-bootstrap-dialog';
 import { t } from '@superset-ui/translation';
@@ -158,8 +159,8 @@ const DatasourceModal: 
FunctionComponent<DatasourceModalProps> = ({
       <Modal.Footer>
         <span className="float-left">
           <Button
-            bsSize="sm"
-            bsStyle="default"
+            buttonSize="sm"
+            buttonStyle="default"
             target="_blank"
             href={currentDatasource.edit_url || currentDatasource.url}
           >
@@ -169,15 +170,16 @@ const DatasourceModal: 
FunctionComponent<DatasourceModalProps> = ({
 
         <span className="float-right">
           <Button
-            bsSize="sm"
-            bsStyle="primary"
+            buttonSize="sm"
+            buttonStyle="primary"
             className="m-r-5"
+            data-test="datasource-modal-save"
             onClick={onClickSave}
             disabled={errors.length > 0}
           >
             {t('Save')}
           </Button>
-          <Button bsSize="sm" onClick={onHide}>
+          <Button buttonSize="sm" onClick={onHide}>
             {t('Cancel')}
           </Button>
           <Dialog ref={dialog} />
diff --git 
a/superset-frontend/src/explore/components/AdhocFilterEditPopover.jsx 
b/superset-frontend/src/explore/components/AdhocFilterEditPopover.jsx
index 7fc48b6..e28e118 100644
--- a/superset-frontend/src/explore/components/AdhocFilterEditPopover.jsx
+++ b/superset-frontend/src/explore/components/AdhocFilterEditPopover.jsx
@@ -18,7 +18,9 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button, Popover, Tab, Tabs } from 'react-bootstrap';
+import { Popover, Tab, Tabs } from 'react-bootstrap';
+import Button from 'src/components/Button';
+import { ThemeProvider } from '@superset-ui/style';
 
 import columnType from '../propTypes/columnType';
 import adhocMetricType from '../propTypes/adhocMetricType';
@@ -40,6 +42,7 @@ const propTypes = {
   ).isRequired,
   datasource: PropTypes.object,
   partitionColumn: PropTypes.string,
+  theme: PropTypes.object,
 };
 
 const startingWidth = 300;
@@ -119,6 +122,7 @@ export default class AdhocFilterEditPopover extends 
React.Component {
       onResize,
       datasource,
       partitionColumn,
+      theme,
       ...popoverProps
     } = this.props;
 
@@ -129,68 +133,74 @@ export default class AdhocFilterEditPopover extends 
React.Component {
 
     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"
+        <ThemeProvider theme={theme}>
+          <Tabs
+            id="adhoc-filter-edit-tabs"
+            defaultActiveKey={adhocFilter.expressionType}
+            className="adhoc-filter-edit-tabs"
+            style={{ height: this.state.height, width: this.state.width }}
           >
-            <AdhocFilterEditPopoverSimpleTabContent
-              adhocFilter={this.state.adhocFilter}
-              onChange={this.onAdhocFilterChange}
-              options={options}
-              datasource={datasource}
-              onHeightChange={this.adjustHeight}
-              partitionColumn={partitionColumn}
-            />
-          </Tab>
-          <Tab
-            className="adhoc-filter-edit-tab"
-            eventKey={EXPRESSION_TYPES.SQL}
-            title="Custom SQL"
-          >
-            {!this.props.datasource ||
-            this.props.datasource.type !== 'druid' ? (
-              <AdhocFilterEditPopoverSqlTabContent
+            <Tab
+              className="adhoc-filter-edit-tab"
+              eventKey={EXPRESSION_TYPES.SIMPLE}
+              title="Simple"
+            >
+              <AdhocFilterEditPopoverSimpleTabContent
                 adhocFilter={this.state.adhocFilter}
                 onChange={this.onAdhocFilterChange}
-                options={this.props.options}
-                height={this.state.height}
+                options={options}
+                datasource={datasource}
+                onHeightChange={this.adjustHeight}
+                partitionColumn={partitionColumn}
               />
-            ) : (
-              <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
-            role="button"
-            tabIndex={0}
-            onMouseDown={this.onDragDown}
-            className="fa fa-expand edit-popover-resize text-muted"
-          />
-        </div>
+            </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}
+              buttonStyle={
+                hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
+              }
+              buttonSize="small"
+              className="m-r-5"
+              onClick={this.onSave}
+              cta
+            >
+              Save
+            </Button>
+            <Button buttonSize="small" onClick={this.props.onClose} cta>
+              Close
+            </Button>
+            <i
+              role="button"
+              tabIndex={0}
+              onMouseDown={this.onDragDown}
+              className="fa fa-expand edit-popover-resize text-muted"
+            />
+          </div>
+        </ThemeProvider>
       </Popover>
     );
   }
 }
+
 AdhocFilterEditPopover.propTypes = propTypes;
diff --git a/superset-frontend/src/explore/components/AdhocFilterOption.jsx 
b/superset-frontend/src/explore/components/AdhocFilterOption.jsx
index 7d05454..1ba5ef1 100644
--- a/superset-frontend/src/explore/components/AdhocFilterOption.jsx
+++ b/superset-frontend/src/explore/components/AdhocFilterOption.jsx
@@ -21,6 +21,7 @@ import PropTypes from 'prop-types';
 import { OverlayTrigger } from 'react-bootstrap';
 import { t } from '@superset-ui/translation';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
+import { withTheme } from '@superset-ui/style';
 
 import Label from 'src/components/Label';
 import AdhocFilterEditPopover from './AdhocFilterEditPopover';
@@ -41,8 +42,7 @@ const propTypes = {
   datasource: PropTypes.object,
   partitionColumn: PropTypes.string,
 };
-
-export default class AdhocFilterOption extends React.PureComponent {
+class AdhocFilterOption extends React.PureComponent {
   constructor(props) {
     super(props);
     this.closeFilterEditOverlay = this.closeFilterEditOverlay.bind(this);
@@ -73,7 +73,7 @@ export default class AdhocFilterOption extends 
React.PureComponent {
   }
 
   render() {
-    const { adhocFilter } = this.props;
+    const { adhocFilter, theme } = this.props;
     const overlay = (
       <AdhocFilterEditPopover
         onResize={this.onPopoverResize}
@@ -83,6 +83,7 @@ export default class AdhocFilterOption extends 
React.PureComponent {
         options={this.props.options}
         datasource={this.props.datasource}
         partitionColumn={this.props.partitionColumn}
+        theme={theme}
       />
     );
     return (
@@ -123,4 +124,7 @@ export default class AdhocFilterOption extends 
React.PureComponent {
     );
   }
 }
+
+export default withTheme(AdhocFilterOption);
+
 AdhocFilterOption.propTypes = propTypes;
diff --git 
a/superset-frontend/src/explore/components/AdhocMetricEditPopover.jsx 
b/superset-frontend/src/explore/components/AdhocMetricEditPopover.jsx
index e94a7bb..4e8d577 100644
--- a/superset-frontend/src/explore/components/AdhocMetricEditPopover.jsx
+++ b/superset-frontend/src/explore/components/AdhocMetricEditPopover.jsx
@@ -18,7 +18,8 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button, FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
+import { FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Select from 'src/components/Select';
 import ace from 'brace';
 import AceEditor from 'react-ace';
@@ -27,6 +28,7 @@ import 'brace/theme/github';
 import 'brace/ext/language_tools';
 import { t } from '@superset-ui/translation';
 import { ColumnOption } from '@superset-ui/chart-controls';
+import { ThemeProvider } from '@superset-ui/style';
 
 import FormLabel from 'src/components/FormLabel';
 
@@ -45,6 +47,7 @@ const propTypes = {
   onResize: PropTypes.func.isRequired,
   columns: PropTypes.arrayOf(columnType),
   datasourceType: PropTypes.string,
+  theme: PropTypes.object,
 };
 
 const defaultProps = {
@@ -192,6 +195,7 @@ export default class AdhocMetricEditPopover extends 
React.Component {
       onClose,
       onResize,
       datasourceType,
+      theme,
       ...popoverProps
     } = this.props;
 
@@ -232,98 +236,104 @@ export default class AdhocMetricEditPopover extends 
React.Component {
     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"
+        <ThemeProvider theme={theme}>
+          <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}
           >
-            <FormGroup>
-              <FormLabel>
-                <strong>column</strong>
-              </FormLabel>
-              <Select
-                name="select-column"
-                {...this.selectProps}
-                {...columnSelectProps}
-              />
-            </FormGroup>
-            <FormGroup>
-              <FormLabel>
-                <strong>aggregate</strong>
-              </FormLabel>
-              <Select
-                name="select-aggregate"
-                {...this.selectProps}
-                {...aggregateSelectProps}
-                autoFocus
-              />
-            </FormGroup>
-          </Tab>
-          <Tab
-            className="adhoc-metric-edit-tab"
-            eventKey={EXPRESSION_TYPES.SQL}
-            title="Custom SQL"
-            data-test="adhoc-metric-edit-tab#custom"
-          >
-            {this.props.datasourceType !== 'druid' ? (
+            <Tab
+              className="adhoc-metric-edit-tab"
+              eventKey={EXPRESSION_TYPES.SIMPLE}
+              title="Simple"
+            >
               <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
+                <FormLabel>
+                  <strong>column</strong>
+                </FormLabel>
+                <Select
+                  name="select-column"
+                  {...this.selectProps}
+                  {...columnSelectProps}
                 />
               </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"
-            data-test="AdhocMetricEdit#save"
-            onClick={this.onSave}
-          >
-            Save
-          </Button>
-          <Button
-            bsSize="small"
-            onClick={this.props.onClose}
-            data-test="AdhocMetricEdit#cancel"
-          >
-            Close
-          </Button>
-          <i
-            role="button"
-            tabIndex={0}
-            onMouseDown={this.onDragDown}
-            className="fa fa-expand edit-popover-resize text-muted"
-          />
-        </div>
+              <FormGroup>
+                <FormLabel>
+                  <strong>aggregate</strong>
+                </FormLabel>
+                <Select
+                  name="select-aggregate"
+                  {...this.selectProps}
+                  {...aggregateSelectProps}
+                  autoFocus
+                />
+              </FormGroup>
+            </Tab>
+            <Tab
+              className="adhoc-metric-edit-tab"
+              eventKey={EXPRESSION_TYPES.SQL}
+              title="Custom SQL"
+              data-test="adhoc-metric-edit-tab#custom"
+            >
+              {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}
+              buttonStyle={
+                hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
+              }
+              buttonSize="small"
+              className="m-r-5"
+              data-test="AdhocMetricEdit#save"
+              onClick={this.onSave}
+              cta
+            >
+              Save
+            </Button>
+            <Button
+              buttonSize="small"
+              onClick={this.props.onClose}
+              data-test="AdhocMetricEdit#cancel"
+              cta
+            >
+              Close
+            </Button>
+            <i
+              role="button"
+              tabIndex={0}
+              onMouseDown={this.onDragDown}
+              className="fa fa-expand edit-popover-resize text-muted"
+            />
+          </div>
+        </ThemeProvider>
       </Popover>
     );
   }
diff --git a/superset-frontend/src/explore/components/AdhocMetricOption.jsx 
b/superset-frontend/src/explore/components/AdhocMetricOption.jsx
index 945107c..7d84697 100644
--- a/superset-frontend/src/explore/components/AdhocMetricOption.jsx
+++ b/superset-frontend/src/explore/components/AdhocMetricOption.jsx
@@ -19,6 +19,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { OverlayTrigger } from 'react-bootstrap';
+import { withTheme } from '@superset-ui/style';
 
 import Label from 'src/components/Label';
 import AdhocMetricEditPopover from './AdhocMetricEditPopover';
@@ -33,7 +34,7 @@ const propTypes = {
   datasourceType: PropTypes.string,
 };
 
-export default class AdhocMetricOption extends React.PureComponent {
+class AdhocMetricOption extends React.PureComponent {
   constructor(props) {
     super(props);
     this.closeMetricEditOverlay = this.closeMetricEditOverlay.bind(this);
@@ -65,7 +66,7 @@ export default class AdhocMetricOption extends 
React.PureComponent {
   }
 
   render() {
-    const { adhocMetric } = this.props;
+    const { adhocMetric, theme } = this.props;
     const overlayContent = (
       <AdhocMetricEditPopover
         onResize={this.onPopoverResize}
@@ -74,6 +75,7 @@ export default class AdhocMetricOption extends 
React.PureComponent {
         onClose={this.closeMetricEditOverlay}
         columns={this.props.columns}
         datasourceType={this.props.datasourceType}
+        theme={theme}
       />
     );
 
@@ -109,4 +111,7 @@ export default class AdhocMetricOption extends 
React.PureComponent {
     );
   }
 }
+
+export default withTheme(AdhocMetricOption);
+
 AdhocMetricOption.propTypes = propTypes;
diff --git a/superset-frontend/src/explore/components/DisplayQueryButton.jsx 
b/superset-frontend/src/explore/components/DisplayQueryButton.jsx
index aa41f11..495bf61 100644
--- a/superset-frontend/src/explore/components/DisplayQueryButton.jsx
+++ b/superset-frontend/src/explore/components/DisplayQueryButton.jsx
@@ -38,13 +38,13 @@ import {
 import { Table } from 'reactable-arc';
 import { t } from '@superset-ui/translation';
 
+import Button from 'src/components/Button';
 import getClientErrorObject from '../../utils/getClientErrorObject';
 import CopyToClipboard from './../../components/CopyToClipboard';
 import { getChartDataRequest } from '../../chart/chartAction';
 import downloadAsImage from '../../utils/downloadAsImage';
 import Loading from '../../components/Loading';
 import ModalTrigger from './../../components/ModalTrigger';
-import Button from '../../components/Button';
 import RowCountLabel from './RowCountLabel';
 import {
   applyFormattingToTabularData,
diff --git a/superset-frontend/src/explore/components/ExploreActionButtons.jsx 
b/superset-frontend/src/explore/components/ExploreActionButtons.jsx
index 08757fe..7b45d9d 100644
--- a/superset-frontend/src/explore/components/ExploreActionButtons.jsx
+++ b/superset-frontend/src/explore/components/ExploreActionButtons.jsx
@@ -47,7 +47,7 @@ export default function ExploreActionButtons({
   slice,
 }) {
   const exportToCSVClasses = cx('btn btn-default btn-sm', {
-    'disabled disabledButton': !canDownload,
+    disabled: !canDownload,
   });
   const doExportCSV = exportChart.bind(this, {
     formData: latestQueryFormData,
diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx 
b/superset-frontend/src/explore/components/PropertiesModal.tsx
index bbcb508..8b5d76d 100644
--- a/superset-frontend/src/explore/components/PropertiesModal.tsx
+++ b/superset-frontend/src/explore/components/PropertiesModal.tsx
@@ -18,7 +18,6 @@
  */
 import React, { useState, useEffect, useRef } from 'react';
 import {
-  Button,
   Modal,
   Row,
   Col,
@@ -26,6 +25,7 @@ import {
   FormGroup,
   // @ts-ignore
 } from 'react-bootstrap';
+import Button from 'src/components/Button';
 // @ts-ignore
 import Dialog from 'react-bootstrap-dialog';
 import { OptionsType } from 'react-select/src/types';
@@ -263,15 +263,15 @@ function PropertiesModal({ slice, onHide, onSave }: 
InternalProps) {
         </Row>
       </Modal.Body>
       <Modal.Footer>
-        <Button type="button" bsSize="sm" onClick={onHide}>
+        <Button type="button" buttonSize="sm" onClick={onHide} cta>
           {t('Cancel')}
         </Button>
         <Button
           type="submit"
-          bsSize="sm"
-          bsStyle="primary"
-          className="m-r-5"
+          buttonSize="sm"
+          buttonStyle="primary"
           disabled={!owners || submitting || !name}
+          cta
         >
           {t('Save')}
         </Button>
diff --git a/superset-frontend/src/explore/components/QueryAndSaveBtns.jsx 
b/superset-frontend/src/explore/components/QueryAndSaveBtns.jsx
index a8bba79..d39fa6a 100644
--- a/superset-frontend/src/explore/components/QueryAndSaveBtns.jsx
+++ b/superset-frontend/src/explore/components/QueryAndSaveBtns.jsx
@@ -19,11 +19,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { ButtonGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
-import classnames from 'classnames';
 import { t } from '@superset-ui/translation';
 import styled from '@superset-ui/style';
 
-import Button from '../../components/Button';
+import Button from 'src/components/Button';
 import Hotkeys from '../../components/Hotkeys';
 
 const propTypes = {
@@ -61,7 +60,8 @@ const Styles = styled.div`
   align-items: center;
   padding-bottom: ${({ theme }) => 2 * theme.gridUnit}px;
 
-  .save-btn {
+  .btn {
+    /* just to make sure buttons don't jiggle */
     width: 100px;
   }
 `;
@@ -75,12 +75,7 @@ export default function QueryAndSaveBtns({
   chartIsStale,
   errorMessage,
 }) {
-  const saveClasses = classnames({
-    'disabled disabledButton': !canAdd,
-    'save-btn': true,
-  });
-
-  let qryButtonStyle = 'default';
+  let qryButtonStyle = 'secondary';
   if (errorMessage) {
     qryButtonStyle = 'danger';
   } else if (chartIsStale) {
@@ -89,15 +84,21 @@ export default function QueryAndSaveBtns({
 
   const saveButtonDisabled = errorMessage ? true : loading;
   const qryOrStopButton = loading ? (
-    <Button onClick={onStop} bsStyle="warning" className="save-btn">
+    <Button
+      onClick={onStop}
+      buttonStyle="warning"
+      buttonSize="small"
+      disabled={!canAdd}
+    >
       <i className="fa fa-stop-circle-o" /> Stop
     </Button>
   ) : (
     <Button
-      className="query save-btn"
+      buttonSize="small"
       onClick={onQuery}
-      bsStyle={qryButtonStyle}
+      buttonStyle={qryButtonStyle}
       disabled={!!errorMessage}
+      data-test="run-query-button"
     >
       <i className="fa fa-bolt" /> {t('Run')}
     </Button>
@@ -109,7 +110,8 @@ export default function QueryAndSaveBtns({
         <ButtonGroup className="query-and-save">
           {qryOrStopButton}
           <Button
-            className={saveClasses}
+            buttonStyle="secondary"
+            buttonSize="small"
             data-target="#save_modal"
             data-toggle="modal"
             disabled={saveButtonDisabled}
diff --git a/superset-frontend/src/explore/components/SaveModal.jsx 
b/superset-frontend/src/explore/components/SaveModal.jsx
index 804ebc2..e57189b 100644
--- a/superset-frontend/src/explore/components/SaveModal.jsx
+++ b/superset-frontend/src/explore/components/SaveModal.jsx
@@ -20,14 +20,8 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
-import {
-  Alert,
-  Button,
-  FormControl,
-  FormGroup,
-  Modal,
-  Radio,
-} from 'react-bootstrap';
+import { Alert, FormControl, FormGroup, Modal, Radio } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import FormLabel from 'src/components/FormLabel';
 import { CreatableSelect } from 'src/components/Select/SupersetStyledSelect';
 import { t } from '@superset-ui/translation';
@@ -208,18 +202,12 @@ class SaveModal extends React.Component {
 
         <Modal.Footer>
           <div className="float-right">
-            <Button
-              type="button"
-              id="btn_cancel"
-              bsSize="sm"
-              onClick={this.props.onHide}
-            >
+            <Button id="btn_cancel" buttonSize="sm" 
onClick={this.props.onHide}>
               {t('Cancel')}
             </Button>
             <Button
-              type="button"
               id="btn_modal_save_goto_dash"
-              bsSize="sm"
+              buttonSize="sm"
               disabled={
                 !this.state.newSliceName || !this.state.newDashboardName
               }
@@ -228,10 +216,9 @@ class SaveModal extends React.Component {
               {t('Save & go to dashboard')}
             </Button>
             <Button
-              type="button"
               id="btn_modal_save"
-              bsSize="sm"
-              bsStyle="primary"
+              buttonSize="sm"
+              buttonStyle="primary"
               onClick={this.saveOrOverwrite.bind(this, false)}
               disabled={!this.state.newSliceName}
             >
diff --git 
a/superset-frontend/src/explore/components/controls/AnnotationLayer.jsx 
b/superset-frontend/src/explore/components/controls/AnnotationLayer.jsx
index e119e87..d90cdd1 100644
--- a/superset-frontend/src/explore/components/controls/AnnotationLayer.jsx
+++ b/superset-frontend/src/explore/components/controls/AnnotationLayer.jsx
@@ -19,13 +19,14 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { CompactPicker } from 'react-color';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import mathjs from 'mathjs';
 import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/connection';
 import { getCategoricalSchemeRegistry } from '@superset-ui/color';
 import { getChartMetadataRegistry } from '@superset-ui/chart';
 import { validateNonEmpty } from '@superset-ui/validator';
+import { ThemeProvider } from '@superset-ui/style';
 
 import SelectControl from './SelectControl';
 import TextControl from './TextControl';
@@ -63,6 +64,7 @@ const propTypes = {
   timeColumn: PropTypes.string,
   intervalEndColumn: PropTypes.string,
   vizType: PropTypes.string,
+  theme: PropTypes.object,
 
   error: PropTypes.string,
   colorScheme: PropTypes.string,
@@ -619,8 +621,8 @@ export default class AnnotationLayer extends 
React.PureComponent {
             />
             <Button
               style={{ marginTop: '0.5rem', marginBottom: '0.5rem' }}
-              bsStyle={color === AUTOMATIC_COLOR ? 'success' : 'default'}
-              bsSize="xsmall"
+              buttonStyle={color === AUTOMATIC_COLOR ? 'success' : 'default'}
+              buttonSize="xsmall"
               onClick={() => this.setState({ color: AUTOMATIC_COLOR })}
             >
               Automatic Color
@@ -661,7 +663,7 @@ export default class AnnotationLayer extends 
React.PureComponent {
   render() {
     const { isNew, name, annotationType, sourceType, show } = this.state;
     const isValid = this.isValidForm();
-
+    const { theme } = this.props;
     const metadata = getChartMetadataRegistry().get(this.props.vizType);
     const supportedAnnotationTypes = metadata
       ? metadata.supportedAnnotationTypes.map(
@@ -671,7 +673,7 @@ export default class AnnotationLayer extends 
React.PureComponent {
     const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
 
     return (
-      <div>
+      <ThemeProvider theme={theme}>
         {this.props.error && (
           <span style={{ color: 'red' }}>ERROR: {this.props.error}</span>
         )}
@@ -724,12 +726,12 @@ export default class AnnotationLayer extends 
React.PureComponent {
           {this.renderDisplayConfiguration()}
         </div>
         <div style={{ display: 'flex', justifyContent: 'space-between' }}>
-          <Button bsSize="sm" onClick={this.deleteAnnotation}>
+          <Button buttonSize="sm" onClick={this.deleteAnnotation}>
             {!isNew ? t('Remove') : t('Cancel')}
           </Button>
           <div>
             <Button
-              bsSize="sm"
+              buttonSize="sm"
               disabled={!isValid}
               onClick={this.applyAnnotation}
             >
@@ -737,7 +739,7 @@ export default class AnnotationLayer extends 
React.PureComponent {
             </Button>
 
             <Button
-              bsSize="sm"
+              buttonSize="sm"
               disabled={!isValid}
               onClick={this.submitAnnotation}
             >
@@ -745,7 +747,7 @@ export default class AnnotationLayer extends 
React.PureComponent {
             </Button>
           </div>
         </div>
-      </div>
+      </ThemeProvider>
     );
   }
 }
diff --git 
a/superset-frontend/src/explore/components/controls/AnnotationLayerControl.jsx 
b/superset-frontend/src/explore/components/controls/AnnotationLayerControl.jsx
index d0b5229..3eb594c 100644
--- 
a/superset-frontend/src/explore/components/controls/AnnotationLayerControl.jsx
+++ 
b/superset-frontend/src/explore/components/controls/AnnotationLayerControl.jsx
@@ -26,6 +26,7 @@ import {
 } from 'react-bootstrap';
 import { connect } from 'react-redux';
 import { t } from '@superset-ui/translation';
+import { withTheme } from '@superset-ui/style';
 import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
 import { getChartKey } from '../../exploreUtils';
 import { runAnnotationQuery } from '../../../chart/chartAction';
@@ -100,6 +101,7 @@ class AnnotationLayerControl extends React.PureComponent {
 
   renderPopover(parent, annotation, error) {
     const id = !annotation ? '_new' : annotation.name;
+    const { theme } = this.props;
     return (
       <Popover
         style={{ maxWidth: 'none' }}
@@ -116,6 +118,7 @@ class AnnotationLayerControl extends React.PureComponent {
           addAnnotationLayer={this.addAnnotationLayer}
           removeAnnotationLayer={this.removeAnnotationLayer}
           close={() => this.refs[parent].hide()}
+          theme={theme}
         />
       </Popover>
     );
@@ -208,7 +211,9 @@ function mapDispatchToProps(dispatch) {
   };
 }
 
+const themedAnnotationLayerControl = withTheme(AnnotationLayerControl);
+
 export default connect(
   mapStateToProps,
   mapDispatchToProps,
-)(AnnotationLayerControl);
+)(themedAnnotationLayerControl);
diff --git 
a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx 
b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
index 538123c..8e02c60 100644
--- a/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
+++ b/superset-frontend/src/explore/components/controls/DateFilterControl.jsx
@@ -19,7 +19,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import {
-  Button,
   DropdownButton,
   FormControl,
   FormGroup,
@@ -32,6 +31,7 @@ import {
   Tabs,
   Tooltip,
 } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import Datetime from 'react-datetime';
 import 'react-datetime/css/react-datetime.css';
 import moment from 'moment';
@@ -365,7 +365,7 @@ class DateFilterControl extends React.Component {
             onClick={() => {}}
           />
           <InputGroup.Button onClick={() => this.toggleCalendar(key)}>
-            <Button>
+            <Button theme={this.props.theme}>
               <i className="fa fa-calendar" />
             </Button>
           </InputGroup.Button>
@@ -563,10 +563,11 @@ class DateFilterControl extends React.Component {
           </Tabs>
           <div className="clearfix">
             <Button
-              bsSize="small"
+              buttonSize="small"
               className="float-right ok"
-              bsStyle="primary"
+              buttonStyle="primary"
               onClick={this.close}
+              theme={this.props.theme}
             >
               Ok
             </Button>
diff --git 
a/superset-frontend/src/explore/components/controls/SpatialControl.jsx 
b/superset-frontend/src/explore/components/controls/SpatialControl.jsx
index f9cdecb..4bef1b2 100644
--- a/superset-frontend/src/explore/components/controls/SpatialControl.jsx
+++ b/superset-frontend/src/explore/components/controls/SpatialControl.jsx
@@ -18,7 +18,8 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Row, Col, Button, OverlayTrigger, Popover } from 'react-bootstrap';
+import { Row, Col, OverlayTrigger, Popover } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 
 import Label from 'src/components/Label';
@@ -204,9 +205,9 @@ export default class SpatialControl extends React.Component 
{
           </PopoverSection>
           <div className="clearfix">
             <Button
-              bsSize="small"
+              buttonSize="small"
               className="float-left ok"
-              bsStyle="primary"
+              buttonStyle="primary"
               onClick={this.close.bind(this)}
             >
               Ok
diff --git 
a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx 
b/superset-frontend/src/explore/components/controls/TextAreaControl.jsx
index 4cb607b..0a09f93 100644
--- a/superset-frontend/src/explore/components/controls/TextAreaControl.jsx
+++ b/superset-frontend/src/explore/components/controls/TextAreaControl.jsx
@@ -18,7 +18,8 @@
  */
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Button, FormGroup, FormControl } from 'react-bootstrap';
+import { FormGroup, FormControl } from 'react-bootstrap';
+import Button from 'src/components/Button';
 
 import AceEditor from 'react-ace';
 import 'brace/mode/sql';
@@ -121,7 +122,7 @@ export default class TextAreaControl extends 
React.Component {
             bsSize="large"
             modalTitle={controlHeader}
             triggerNode={
-              <Button bsSize="small" className="m-t-5">
+              <Button buttonSize="small" className="m-t-5">
                 {t('Edit')} <strong>{this.props.language}</strong>{' '}
                 {t('in modal')}
               </Button>
diff --git a/superset-frontend/src/views/CRUD/data/dataset/Button.tsx 
b/superset-frontend/src/views/CRUD/data/dataset/Button.tsx
deleted file mode 100644
index f0125e9..0000000
--- a/superset-frontend/src/views/CRUD/data/dataset/Button.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import React from 'react';
-import styled from '@superset-ui/style';
-import BaseButton from 'src/components/Button';
-
-interface ModalProps {
-  children: React.ReactNode;
-  disabled?: boolean;
-  onClick: () => void;
-  padding?: number;
-  bsStyle?: 'default' | 'primary' | 'danger';
-  width?: number;
-}
-
-const StyledButton = styled(BaseButton)`
-  border-radius: ${({ theme }) => theme.borderRadius}px;
-  border: none;
-  padding: ${(props: ModalProps) => props.padding || 8}px;
-  text-transform: uppercase;
-  width: ${(props: ModalProps) => props.width || 160}px;
-
-  &.btn,
-  &.btn:hover {
-    background-color: ${({ theme }) => theme.colors.primary.light4};
-    color: ${({ theme }) => theme.colors.primary.base};
-  }
-  &.btn[disabled],
-  &.btn[disabled]:hover {
-    background-color: ${({ theme }) => theme.colors.grayscale.light2};
-    color: ${({ theme }) => theme.colors.grayscale.light1};
-  }
-  &.btn-primary,
-  &.btn-primary:hover {
-    background-color: ${({ theme }) => theme.colors.primary.base};
-    color: ${({ theme }) => theme.colors.grayscale.light5};
-  }
-  &.btn-danger,
-  &.btn-danger:hover {
-    background-color: ${({ theme }) => theme.colors.error.base};
-    color: ${({ theme }) => theme.colors.grayscale.light5};
-  }
-`;
-
-export default function Modal({
-  bsStyle = 'default',
-  disabled,
-  onClick,
-  children,
-}: ModalProps) {
-  return (
-    <StyledButton disabled={disabled} bsStyle={bsStyle} onClick={onClick}>
-      {children}
-    </StyledButton>
-  );
-}
diff --git a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx 
b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
index 66b4fbe..f799430 100644
--- a/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
+++ b/superset-frontend/src/visualizations/FilterBox/FilterBox.jsx
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
 import { debounce } from 'lodash';
 import { max as d3Max } from 'd3-array';
 import { AsyncCreatableSelect, CreatableSelect } from 'src/components/Select';
-import { Button } from 'react-bootstrap';
+import Button from 'src/components/Button';
 import { t } from '@superset-ui/translation';
 import { SupersetClient } from '@superset-ui/connection';
 import styled from '@superset-ui/style';
@@ -438,8 +438,8 @@ class FilterBox extends React.Component {
         {this.renderFilters()}
         {!instantFiltering && (
           <Button
-            bsSize="small"
-            bsStyle="primary"
+            buttonSize="small"
+            buttonStyle="primary"
             onClick={this.clickApply.bind(this)}
             disabled={!this.state.hasChanged}
           >
diff --git a/superset-frontend/stylesheets/superset.less 
b/superset-frontend/stylesheets/superset.less
index 1560d67..6a06c92 100644
--- a/superset-frontend/stylesheets/superset.less
+++ b/superset-frontend/stylesheets/superset.less
@@ -196,6 +196,10 @@ table.table-no-hover tr:hover {
   background-color: initial;
 }
 
+.editable-title {
+  margin-right: 8px;
+}
+
 .editable-title input {
   outline: none;
   background: transparent;
diff --git a/superset/assets/src/SqlLab/components/ExploreCtasResultsButton.jsx 
b/superset/assets/src/SqlLab/components/ExploreCtasResultsButton.jsx
index f4b5e6f..a0601a1 100644
--- a/superset/assets/src/SqlLab/components/ExploreCtasResultsButton.jsx
+++ b/superset/assets/src/SqlLab/components/ExploreCtasResultsButton.jsx
@@ -26,7 +26,7 @@ import { InfoTooltipWithTrigger } from 
'@superset-ui/chart-controls';
 
 import { exploreChart } from '../../explore/exploreUtils';
 import * as actions from '../actions/sqlLab';
-import Button from '../../components/Button';
+import Button from 'src/components/Button';
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
@@ -88,7 +88,7 @@ class ExploreCtasResultsButton extends React.PureComponent {
     return (
       <>
         <Button
-          bsSize="small"
+          buttonSize="small"
           onClick={this.onClick}
           tooltip={t('Explore the result set in the data exploration view')}
         >

Reply via email to