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

ccwilliams 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 19ac6e1  get rid of global `notify` (#5355)
19ac6e1 is described below

commit 19ac6e1231c6ecedb651a83b60a151672e6abbe0
Author: Chris Williams <willias...@users.noreply.github.com>
AuthorDate: Thu Jul 12 11:50:25 2018 -0700

    get rid of global `notify` (#5355)
    
    * [toasts] get rid of notify globals, refactor messageToasts for use by 
entire app
    
    * [remove notify] use arrow func in ajax call
    
    * fix lint + tests
    
    * actually fix tests from messageToast refactor
    
    * add 'test:one' npm script
    
    * debugger
    
    * [toasts] convert bootstrap flash messages to toasts in explore + sqllab
    
    * [toasts][tests] import from right file
---
 superset/assets/package.json                       |   2 +-
 .../components/URLShortLinkButton_spec.jsx         |  12 +-
 .../dashboard/actions/dashboardLayout_spec.js      |   2 +-
 .../javascripts/dashboard/fixtures/mockState.js    |   2 +-
 .../explore/components/DatasourceControl_spec.jsx  |  14 +-
 .../components/MetricDefinitionOption_spec.jsx     |  15 +-
 .../spec/javascripts/messageToasts/.eslintrc       |  33 +++
 .../spec/javascripts/messageToasts/.prettierrc     |   4 +
 .../components/ToastPresenter_spec.jsx             |   6 +-
 .../components/Toast_spec.jsx                      |   4 +-
 .../mockMessageToasts.js                           |   5 +-
 .../reducers/messageToasts_spec.js                 |   7 +-
 .../utils/getToastsFromPyFlashMessages_spec.js     |  35 ++++
 .../spec/javascripts/sqllab/AlertsWrapper_spec.jsx |  31 ---
 .../assets/spec/javascripts/sqllab/App_spec.jsx    |   9 +-
 .../javascripts/sqllab/CopyQueryTabUrl_spec.jsx    |   2 +-
 .../javascripts/sqllab/SqlEditorLeftBar_spec.jsx   |   1 +
 .../spec/javascripts/sqllab/SqlEditor_spec.jsx     |   2 +-
 .../javascripts/sqllab/TabbedSqlEditors_spec.jsx   |   8 +-
 .../javascripts/sqllab/VisualizeModal_spec.jsx     |  44 ++--
 .../assets/spec/javascripts/sqllab/actions_spec.js |   6 +-
 .../assets/spec/javascripts/sqllab/fixtures.js     |  21 +-
 .../spec/javascripts/sqllab/reducers_spec.js       |  27 +--
 superset/assets/src/SqlLab/actions.js              |  71 ++++---
 superset/assets/src/SqlLab/components/App.jsx      |  30 ++-
 .../src/SqlLab/components/QueryAutoRefresh.jsx     |   6 +-
 .../assets/src/SqlLab/components/QuerySearch.jsx   |   8 +-
 .../assets/src/SqlLab/components/SouthPane.jsx     |   4 +-
 .../assets/src/SqlLab/components/SqlEditor.jsx     |   4 +-
 .../src/SqlLab/components/SqlEditorLeftBar.jsx     |  18 +-
 .../src/SqlLab/components/TabbedSqlEditors.jsx     |  14 +-
 .../src/SqlLab/components/VisualizeModal.jsx       |  14 +-
 superset/assets/src/SqlLab/getInitialState.js      |  33 +++
 superset/assets/src/SqlLab/index.jsx               |  17 +-
 superset/assets/src/SqlLab/reducers.js             |  49 ++---
 superset/assets/src/chart/Chart.jsx                |   4 +-
 superset/assets/src/components/AlertsWrapper.jsx   |  38 ----
 .../assets/src/components/URLShortLinkButton.jsx   |   9 +-
 .../src/dashboard/actions/dashboardLayout.js       |   2 +-
 .../assets/src/dashboard/actions/dashboardState.js |   2 +-
 .../assets/src/dashboard/components/Dashboard.jsx  |   8 +-
 .../src/dashboard/components/DashboardBuilder.jsx  |   2 +-
 .../src/dashboard/containers/DashboardHeader.jsx   |   2 +-
 .../assets/src/dashboard/deprecated/v1/actions.js  |  15 +-
 .../deprecated/v1/components/Dashboard.jsx         |   4 +-
 .../deprecated/v1/components/SaveModal.jsx         |  31 +--
 .../assets/src/dashboard/deprecated/v1/index.jsx   |  10 +-
 .../assets/src/dashboard/deprecated/v1/reducers.js |   3 +
 superset/assets/src/dashboard/reducers/index.js    |   2 +-
 .../assets/src/dashboard/stylesheets/index.less    |   1 -
 superset/assets/src/dashboard/util/constants.js    |   6 -
 superset/assets/src/dashboard/util/propShapes.jsx  |  18 --
 .../explore/components/MetricDefinitionOption.jsx  |   9 +-
 .../components/controls/DatasourceControl.jsx      |  12 +-
 .../components/controls/SelectAsyncControl.jsx     |   9 +-
 superset/assets/src/explore/index.jsx              |  43 ++--
 superset/assets/src/explore/reducers/index.js      |   4 +-
 superset/assets/src/messageToasts/.eslintrc        |  33 +++
 superset/assets/src/messageToasts/.prettierrc      |   4 +
 .../actions/index.js}                              |  11 +-
 .../components/Toast.jsx                           |   5 +-
 .../components/ToastPresenter.jsx                  |   4 +-
 superset/assets/src/messageToasts/constants.js     |   5 +
 .../containers/ToastPresenter.jsx                  |   2 +-
 .../src/messageToasts/enhancers/withToasts.jsx     |  26 +++
 superset/assets/src/messageToasts/propShapes.js    |  21 ++
 .../reducers/index.js}                             |   2 +-
 .../stylesheets/toast.less                         |   6 +-
 .../utils/getToastsFromPyFlashMessages.js          |  22 ++
 superset/assets/src/reduxUtils.js                  |   3 +-
 superset/assets/src/utils/common.js                |  13 +-
 superset/assets/yarn.lock                          | 230 ++++++++-------------
 72 files changed, 657 insertions(+), 524 deletions(-)

diff --git a/superset/assets/package.json b/superset/assets/package.json
index 6a39354..9bcec4d 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -9,6 +9,7 @@
   },
   "scripts": {
     "test": "mocha --require ignore-styles --compilers js:babel-core/register 
--require spec/helpers/browser.js 'spec/**/*_spec.*'",
+    "test:one": "mocha --require ignore-styles --compilers 
js:babel-core/register --require spec/helpers/browser.js",
     "cover": "babel-node node_modules/.bin/babel-istanbul cover _mocha -- 
--require ignore-styles spec/helpers/browser.js 'spec/**/*_spec.*'",
     "dev": "NODE_ENV=dev webpack --watch --colors --progress --debug 
--output-pathinfo --devtool eval-cheap-source-map",
     "dev-slow": "NODE_ENV=dev webpack --watch --colors --progress --debug 
--output-pathinfo --devtool inline-source-map",
@@ -89,7 +90,6 @@
     "react-ace": "^5.10.0",
     "react-addons-css-transition-group": "^15.6.0",
     "react-addons-shallow-compare": "^15.4.2",
-    "react-alert": "^2.3.0",
     "react-bootstrap": "^0.31.5",
     "react-bootstrap-slider": "2.1.5",
     "react-bootstrap-table": "^4.3.1",
diff --git 
a/superset/assets/spec/javascripts/components/URLShortLinkButton_spec.jsx 
b/superset/assets/spec/javascripts/components/URLShortLinkButton_spec.jsx
index 98e6e2c..1aa0074 100644
--- a/superset/assets/spec/javascripts/components/URLShortLinkButton_spec.jsx
+++ b/superset/assets/spec/javascripts/components/URLShortLinkButton_spec.jsx
@@ -1,4 +1,5 @@
 import React from 'react';
+import configureStore from 'redux-mock-store';
 import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
@@ -13,11 +14,14 @@ describe('URLShortLinkButton', () => {
     emailContent: 'mock content',
   };
 
-  it('renders', () => {
-    expect(React.isValidElement(<URLShortLinkButton {...defaultProps} 
/>)).to.equal(true);
-  });
+  function setup() {
+    const mockStore = configureStore([]);
+    const store = mockStore({});
+    return shallow(<URLShortLinkButton {...defaultProps} />, { context: { 
store } }).dive();
+  }
+
   it('renders OverlayTrigger', () => {
-    const wrapper = shallow(<URLShortLinkButton {...defaultProps} />);
+    const wrapper = setup();
     expect(wrapper.find(OverlayTrigger)).have.length(1);
   });
 });
diff --git 
a/superset/assets/spec/javascripts/dashboard/actions/dashboardLayout_spec.js 
b/superset/assets/spec/javascripts/dashboard/actions/dashboardLayout_spec.js
index 4b28480..e58bb11 100644
--- a/superset/assets/spec/javascripts/dashboard/actions/dashboardLayout_spec.js
+++ b/superset/assets/spec/javascripts/dashboard/actions/dashboardLayout_spec.js
@@ -23,7 +23,7 @@ import {
 } from '../../../../src/dashboard/actions/dashboardLayout';
 
 import { setUnsavedChanges } from 
'../../../../src/dashboard/actions/dashboardState';
-import { addInfoToast } from '../../../../src/dashboard/actions/messageToasts';
+import { addInfoToast } from '../../../../src/messageToasts/actions';
 
 import {
   DASHBOARD_GRID_TYPE,
diff --git a/superset/assets/spec/javascripts/dashboard/fixtures/mockState.js 
b/superset/assets/spec/javascripts/dashboard/fixtures/mockState.js
index 655f0bf..514442f 100644
--- a/superset/assets/spec/javascripts/dashboard/fixtures/mockState.js
+++ b/superset/assets/spec/javascripts/dashboard/fixtures/mockState.js
@@ -2,7 +2,7 @@ import chartQueries from './mockChartQueries';
 import { dashboardLayout } from './mockDashboardLayout';
 import dashboardInfo from './mockDashboardInfo';
 import dashboardState from './mockDashboardState';
-import messageToasts from './mockMessageToasts';
+import messageToasts from '../../messageToasts/mockMessageToasts';
 import datasources from './mockDatasource';
 import sliceEntities from './mockSliceEntities';
 
diff --git 
a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
 
b/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
index c8d1390..68dc783 100644
--- 
a/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
+++ 
b/superset/assets/spec/javascripts/explore/components/DatasourceControl_spec.jsx
@@ -1,7 +1,8 @@
 import React from 'react';
 import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
 import { expect } from 'chai';
-import { describe, it, beforeEach } from 'mocha';
+import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
 import { Modal } from 'react-bootstrap';
 import DatasourceControl from 
'../../../../src/explore/components/controls/DatasourceControl';
@@ -26,13 +27,14 @@ const defaultProps = {
 };
 
 describe('DatasourceControl', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<DatasourceControl {...defaultProps} />);
-  });
+  function setup() {
+    const mockStore = configureStore([]);
+    const store = mockStore({});
+    return shallow(<DatasourceControl {...defaultProps} />, { context: { store 
} }).dive();
+  }
 
   it('renders a Modal', () => {
+    const wrapper = setup();
     expect(wrapper.find(Modal)).to.have.lengthOf(1);
   });
 });
diff --git 
a/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
 
b/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
index 1812966..418e9c5 100644
--- 
a/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
+++ 
b/superset/assets/spec/javascripts/explore/components/MetricDefinitionOption_spec.jsx
@@ -1,5 +1,5 @@
-/* eslint-disable no-unused-expressions */
 import React from 'react';
+import configureStore from 'redux-mock-store';
 import { expect } from 'chai';
 import { describe, it } from 'mocha';
 import { shallow } from 'enzyme';
@@ -10,18 +10,25 @@ import ColumnOption from 
'../../../../src/components/ColumnOption';
 import AggregateOption from 
'../../../../src/explore/components/AggregateOption';
 
 describe('MetricDefinitionOption', () => {
+  const mockStore = configureStore([]);
+  const store = mockStore({});
+
+  function setup(props) {
+    return shallow(<MetricDefinitionOption {...props} />, { context: { store } 
}).dive();
+  }
+
   it('renders a MetricOption given a saved metric', () => {
-    const wrapper = shallow(<MetricDefinitionOption option={{ metric_name: 
'a_saved_metric' }} />);
+    const wrapper = setup({ option: { metric_name: 'a_saved_metric' } });
     expect(wrapper.find(MetricOption)).to.have.lengthOf(1);
   });
 
   it('renders a ColumnOption given a column', () => {
-    const wrapper = shallow(<MetricDefinitionOption option={{ column_name: 
'a_column' }} />);
+    const wrapper = setup({ option: { column_name: 'a_column' } });
     expect(wrapper.find(ColumnOption)).to.have.lengthOf(1);
   });
 
   it('renders an AggregateOption given an aggregate metric', () => {
-    const wrapper = shallow(<MetricDefinitionOption option={{ aggregate_name: 
'an_aggregate' }} />);
+    const wrapper = setup({ option: { aggregate_name: 'an_aggregate' } });
     expect(wrapper.find(AggregateOption)).to.have.lengthOf(1);
   });
 });
diff --git a/superset/assets/spec/javascripts/messageToasts/.eslintrc 
b/superset/assets/spec/javascripts/messageToasts/.eslintrc
new file mode 100644
index 0000000..a3f86e3
--- /dev/null
+++ b/superset/assets/spec/javascripts/messageToasts/.eslintrc
@@ -0,0 +1,33 @@
+{
+  "extends": "prettier",
+  "plugins": ["prettier"],
+  "rules": {
+    "prefer-template": 2,
+    "new-cap": 2,
+    "no-restricted-syntax": 2,
+    "guard-for-in": 2,
+    "prefer-arrow-callback": 2,
+    "func-names": 2,
+    "react/jsx-no-bind": 2,
+    "no-confusing-arrow": 2,
+    "jsx-a11y/no-static-element-interactions": 2,
+    "jsx-a11y/anchor-has-content": 2,
+    "react/require-default-props": 2,
+    "no-plusplus": 2,
+    "no-mixed-operators": 0,
+    "no-continue": 2,
+    "no-bitwise": 2,
+    "no-undef": 2,
+    "no-multi-assign": 2,
+    "no-restricted-properties": 2,
+    "no-prototype-builtins": 2,
+    "jsx-a11y/href-no-hash": 2,
+    "class-methods-use-this": 2,
+    "import/no-named-as-default": 2,
+    "import/prefer-default-export": 2,
+    "react/no-unescaped-entities": 2,
+    "react/no-string-refs": 2,
+    "react/jsx-indent": 0,
+    "prettier/prettier": "error"
+  }
+}
diff --git a/superset/assets/spec/javascripts/messageToasts/.prettierrc 
b/superset/assets/spec/javascripts/messageToasts/.prettierrc
new file mode 100644
index 0000000..a20502b
--- /dev/null
+++ b/superset/assets/spec/javascripts/messageToasts/.prettierrc
@@ -0,0 +1,4 @@
+{
+  "singleQuote": true,
+  "trailingComma": "all"
+}
diff --git 
a/superset/assets/spec/javascripts/dashboard/components/ToastPresenter_spec.jsx 
b/superset/assets/spec/javascripts/messageToasts/components/ToastPresenter_spec.jsx
similarity index 82%
rename from 
superset/assets/spec/javascripts/dashboard/components/ToastPresenter_spec.jsx
rename to 
superset/assets/spec/javascripts/messageToasts/components/ToastPresenter_spec.jsx
index 7545ad6..aa04adc 100644
--- 
a/superset/assets/spec/javascripts/dashboard/components/ToastPresenter_spec.jsx
+++ 
b/superset/assets/spec/javascripts/messageToasts/components/ToastPresenter_spec.jsx
@@ -3,9 +3,9 @@ import { shallow } from 'enzyme';
 import { describe, it } from 'mocha';
 import { expect } from 'chai';
 
-import mockMessageToasts from '../fixtures/mockMessageToasts';
-import Toast from '../../../../src/dashboard/components/Toast';
-import ToastPresenter from 
'../../../../src/dashboard/components/ToastPresenter';
+import mockMessageToasts from '../mockMessageToasts';
+import Toast from '../../../../src/messageToasts/components/Toast';
+import ToastPresenter from 
'../../../../src/messageToasts/components/ToastPresenter';
 
 describe('ToastPresenter', () => {
   const props = {
diff --git 
a/superset/assets/spec/javascripts/dashboard/components/Toast_spec.jsx 
b/superset/assets/spec/javascripts/messageToasts/components/Toast_spec.jsx
similarity index 90%
rename from superset/assets/spec/javascripts/dashboard/components/Toast_spec.jsx
rename to 
superset/assets/spec/javascripts/messageToasts/components/Toast_spec.jsx
index 6ed0bc5..ce3396c 100644
--- a/superset/assets/spec/javascripts/dashboard/components/Toast_spec.jsx
+++ b/superset/assets/spec/javascripts/messageToasts/components/Toast_spec.jsx
@@ -4,8 +4,8 @@ import { shallow } from 'enzyme';
 import { describe, it } from 'mocha';
 import { expect } from 'chai';
 
-import mockMessageToasts from '../fixtures/mockMessageToasts';
-import Toast from '../../../../src/dashboard/components/Toast';
+import mockMessageToasts from '../mockMessageToasts';
+import Toast from '../../../../src/messageToasts/components/Toast';
 
 describe('Toast', () => {
   const props = {
diff --git 
a/superset/assets/spec/javascripts/dashboard/fixtures/mockMessageToasts.js 
b/superset/assets/spec/javascripts/messageToasts/mockMessageToasts.js
similarity index 63%
rename from 
superset/assets/spec/javascripts/dashboard/fixtures/mockMessageToasts.js
rename to superset/assets/spec/javascripts/messageToasts/mockMessageToasts.js
index 07726a8..087374c 100644
--- a/superset/assets/spec/javascripts/dashboard/fixtures/mockMessageToasts.js
+++ b/superset/assets/spec/javascripts/messageToasts/mockMessageToasts.js
@@ -1,7 +1,4 @@
-import {
-  INFO_TOAST,
-  DANGER_TOAST,
-} from '../../../../src/dashboard/util/constants';
+import { INFO_TOAST, DANGER_TOAST } from 
'../../../src/messageToasts/constants';
 
 export default [
   { id: 'info_id', toastType: INFO_TOAST, text: 'info toast' },
diff --git 
a/superset/assets/spec/javascripts/dashboard/reducers/messageToasts_spec.js 
b/superset/assets/spec/javascripts/messageToasts/reducers/messageToasts_spec.js
similarity index 79%
rename from 
superset/assets/spec/javascripts/dashboard/reducers/messageToasts_spec.js
rename to 
superset/assets/spec/javascripts/messageToasts/reducers/messageToasts_spec.js
index 5280312..8d71270 100644
--- a/superset/assets/spec/javascripts/dashboard/reducers/messageToasts_spec.js
+++ 
b/superset/assets/spec/javascripts/messageToasts/reducers/messageToasts_spec.js
@@ -1,11 +1,8 @@
 import { describe, it } from 'mocha';
 import { expect } from 'chai';
 
-import {
-  ADD_TOAST,
-  REMOVE_TOAST,
-} from '../../../../src/dashboard/actions/messageToasts';
-import messageToastsReducer from 
'../../../../src/dashboard/reducers/messageToasts';
+import { ADD_TOAST, REMOVE_TOAST } from 
'../../../../src/messageToasts/actions';
+import messageToastsReducer from '../../../../src/messageToasts/reducers';
 
 describe('messageToasts reducer', () => {
   it('should return initial state', () => {
diff --git 
a/superset/assets/spec/javascripts/messageToasts/utils/getToastsFromPyFlashMessages_spec.js
 
b/superset/assets/spec/javascripts/messageToasts/utils/getToastsFromPyFlashMessages_spec.js
new file mode 100644
index 0000000..a3c7ce9
--- /dev/null
+++ 
b/superset/assets/spec/javascripts/messageToasts/utils/getToastsFromPyFlashMessages_spec.js
@@ -0,0 +1,35 @@
+import { describe, it } from 'mocha';
+import { expect } from 'chai';
+
+import {
+  DANGER_TOAST,
+  INFO_TOAST,
+  SUCCESS_TOAST,
+} from '../../../../src/messageToasts/constants';
+
+import getToastsFromPyFlashMessages from 
'../../../../src/messageToasts/utils/getToastsFromPyFlashMessages';
+
+describe('getToastsFromPyFlashMessages', () => {
+  it('should return an info toast', () => {
+    const toast = getToastsFromPyFlashMessages([['info', 'info test']])[0];
+    expect(toast).to.deep.include({ toastType: INFO_TOAST, text: 'info test' 
});
+  });
+
+  it('should return a success toast', () => {
+    const toast = getToastsFromPyFlashMessages([
+      ['success', 'success test'],
+    ])[0];
+    expect(toast).to.deep.include({
+      toastType: SUCCESS_TOAST,
+      text: 'success test',
+    });
+  });
+
+  it('should return a danger toast', () => {
+    const toast = getToastsFromPyFlashMessages([['danger', 'danger test']])[0];
+    expect(toast).to.deep.include({
+      toastType: DANGER_TOAST,
+      text: 'danger test',
+    });
+  });
+});
diff --git a/superset/assets/spec/javascripts/sqllab/AlertsWrapper_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/AlertsWrapper_spec.jsx
deleted file mode 100644
index 9adec4f..0000000
--- a/superset/assets/spec/javascripts/sqllab/AlertsWrapper_spec.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import { describe, it } from 'mocha';
-import { expect } from 'chai';
-import { shallow } from 'enzyme';
-import AlertContainer from 'react-alert';
-import AlertsWrapper from '../../../src/components/AlertsWrapper';
-
-describe('AlertsWrapper', () => {
-  let wrapper;
-
-  beforeEach(() => {
-    wrapper = shallow(<AlertsWrapper />);
-  });
-
-  it('is valid', () => {
-    expect(React.isValidElement(<AlertsWrapper />)).to.equal(true);
-  });
-
-  it('renders AlertContainer', () => {
-    expect(wrapper.find(AlertContainer)).to.have.length(1);
-  });
-
-  it('expects AlertContainer to have correct props', () => {
-    const alertContainerProps = wrapper.find(AlertContainer).props();
-    expect(alertContainerProps.offset).to.be.equal(14);
-    expect(alertContainerProps.position).to.be.equal('top right');
-    expect(alertContainerProps.theme).to.be.equal('dark');
-    expect(alertContainerProps.time).to.be.equal(5000);
-    expect(alertContainerProps.transition).to.be.equal('fade');
-  });
-});
diff --git a/superset/assets/spec/javascripts/sqllab/App_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/App_spec.jsx
index 8d9facb..ce76e30 100644
--- a/superset/assets/spec/javascripts/sqllab/App_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/App_spec.jsx
@@ -14,23 +14,24 @@ import { sqlLabReducer } from 
'../../../src/SqlLab/reducers';
 describe('App', () => {
   const middlewares = [thunk];
   const mockStore = configureStore(middlewares);
-  const store = mockStore(sqlLabReducer(undefined, {}));
+  const store = mockStore({ sqlLab: sqlLabReducer(undefined, {}), 
messageToasts: [] });
 
   let wrapper;
   beforeEach(() => {
-    wrapper = shallow(<App />, {
-      context: { store },
-    }).dive();
+    wrapper = shallow(<App />, { context: { store } }).dive();
   });
+
   it('is valid', () => {
     expect(React.isValidElement(<App />)).to.equal(true);
   });
+
   it('should handler resize', () => {
     sinon.spy(wrapper.instance(), 'getHeight');
     wrapper.instance().handleResize();
     expect(wrapper.instance().getHeight.callCount).to.equal(1);
     wrapper.instance().getHeight.restore();
   });
+
   it('should render', () => {
     expect(wrapper.find('.SqlLab')).to.have.length(1);
     expect(wrapper.find(TabbedSqlEditors)).to.have.length(1);
diff --git a/superset/assets/spec/javascripts/sqllab/CopyQueryTabUrl_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/CopyQueryTabUrl_spec.jsx
index dcbb64e..662cb35 100644
--- a/superset/assets/spec/javascripts/sqllab/CopyQueryTabUrl_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/CopyQueryTabUrl_spec.jsx
@@ -7,7 +7,7 @@ import CopyQueryTabUrl from 
'../../../src/SqlLab/components/CopyQueryTabUrl';
 
 describe('CopyQueryTabUrl', () => {
   const mockedProps = {
-    queryEditor: initialState.queryEditors[0],
+    queryEditor: initialState.sqlLab.queryEditors[0],
   };
   it('is valid with props', () => {
     expect(
diff --git a/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx
index df7035a..16f1f8b 100644
--- a/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx
@@ -20,6 +20,7 @@ describe('SqlEditorLeftBar', () => {
       queryEditorSetDb: sinon.stub(),
       setDatabases: sinon.stub(),
       addTable: sinon.stub(),
+      addDangerToast: sinon.stub(),
     },
     tables: [table],
     queryEditor: defaultQueryEditor,
diff --git a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
index d1b58d3..b068965 100644
--- a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
@@ -11,7 +11,7 @@ describe('SqlEditor', () => {
   const mockedProps = {
     actions: {},
     database: {},
-    queryEditor: initialState.queryEditors[0],
+    queryEditor: initialState.sqlLab.queryEditors[0],
     latestQuery: queries[0],
     tables: [table],
     queries,
diff --git a/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx
index c898662..0846af8 100644
--- a/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx
@@ -22,10 +22,12 @@ describe('TabbedSqlEditors', () => {
     'dfsadfs',
     'newEditorId',
   ];
+
   const tables = [Object.assign({}, table[0], {
     dataPreviewQueryId: 'B1-VQU1zW',
     queryEditorId: 'newEditorId',
   })];
+
   const queryEditors = [{
     autorun: false,
     dbId: 1,
@@ -47,8 +49,8 @@ describe('TabbedSqlEditors', () => {
     databases: {},
     tables: [],
     queries: {},
-    queryEditors: initialState.queryEditors,
-    tabHistory: initialState.tabHistory,
+    queryEditors: initialState.sqlLab.queryEditors,
+    tabHistory: initialState.sqlLab.tabHistory,
     editorHeight: '',
     getHeight: () => ('100px'),
     database: {},
@@ -163,7 +165,7 @@ describe('TabbedSqlEditors', () => {
     wrapper.setState({ hideLeftBar: true });
 
     const firstTab = wrapper.find(Tab).first();
-    
expect(firstTab.props().eventKey).to.contain(initialState.queryEditors[0].id);
+    
expect(firstTab.props().eventKey).to.contain(initialState.sqlLab.queryEditors[0].id);
     expect(firstTab.find(SqlEditor)).to.have.length(1);
 
     const lastTab = wrapper.find(Tab).last();
diff --git a/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx 
b/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx
index b80a962..5eb4802 100644
--- a/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/VisualizeModal_spec.jsx
@@ -17,17 +17,16 @@ import { VISUALIZE_VALIDATION_ERRORS } from 
'../../../src/SqlLab/constants';
 import VisualizeModal from '../../../src/SqlLab/components/VisualizeModal';
 import * as exploreUtils from '../../../src/explore/exploreUtils';
 
-global.notify = {
-  info: () => {},
-  error: () => {},
-};
-
 describe('VisualizeModal', () => {
   const middlewares = [thunk];
   const mockStore = configureStore(middlewares);
-  const initialState = sqlLabReducer({}, {});
-  initialState.common = {
-    conf: { SUPERSET_WEBSERVER_TIMEOUT: 45 },
+  const initialState = {
+    sqlLab: {
+      ...sqlLabReducer(undefined, {}),
+      common: {
+        conf: { SUPERSET_WEBSERVER_TIMEOUT: 45 },
+      },
+    },
   };
   const store = mockStore(initialState);
   const mockedProps = {
@@ -277,7 +276,7 @@ describe('VisualizeModal', () => {
   });
 
   it('should build visualize advise for long query', () => {
-    const longQuery = Object.assign({}, queries[0], { endDttm: 1476910666798 
});
+    const longQuery = { ...queries[0], endDttm: 1476910666798 };
     const props = {
       show: true,
       query: longQuery,
@@ -334,29 +333,46 @@ describe('VisualizeModal', () => {
       expect(spyCall.args[0].data.data).to.equal(JSON.stringify(mockOptions));
     });
     it('should open new window', () => {
+      const infoToastSpy = sinon.spy();
+
       datasourceSpy.callsFake(() => {
         const d = $.Deferred();
         d.resolve('done');
         return d.promise();
       });
-      wrapper.setProps({ actions: { createDatasource: datasourceSpy } });
+
+      wrapper.setProps({
+        actions: {
+          createDatasource: datasourceSpy,
+          addInfoToast: infoToastSpy,
+        },
+      });
 
       wrapper.instance().visualize();
       expect(exploreUtils.exportChart.callCount).to.equal(1);
       
expect(exploreUtils.exportChart.getCall(0).args[0].datasource).to.equal('107__table');
+      expect(infoToastSpy.callCount).to.equal(1);
     });
-    it('should notify error', () => {
+    it('should add error toast', () => {
+      const dangerToastSpy = sinon.spy();
+
       datasourceSpy.callsFake(() => {
         const d = $.Deferred();
         d.reject('error message');
         return d.promise();
       });
-      wrapper.setProps({ actions: { createDatasource: datasourceSpy } });
-      sinon.spy(notify, 'error');
+
+
+      wrapper.setProps({
+        actions: {
+          createDatasource: datasourceSpy,
+          addDangerToast: dangerToastSpy,
+        },
+      });
 
       wrapper.instance().visualize();
       expect(exploreUtils.exportChart.callCount).to.equal(0);
-      expect(notify.error.callCount).to.equal(1);
+      expect(dangerToastSpy.callCount).to.equal(1);
     });
   });
 });
diff --git a/superset/assets/spec/javascripts/sqllab/actions_spec.js 
b/superset/assets/spec/javascripts/sqllab/actions_spec.js
index 34c32a2..5909ca8 100644
--- a/superset/assets/spec/javascripts/sqllab/actions_spec.js
+++ b/superset/assets/spec/javascripts/sqllab/actions_spec.js
@@ -20,13 +20,15 @@ describe('async actions', () => {
 
   describe('saveQuery', () => {
     it('makes the ajax request', () => {
-      actions.saveQuery(query);
+      const thunk = actions.saveQuery(query);
+      thunk((/* mockDispatch */) => {});
       expect(ajaxStub.calledOnce).to.be.true;
     });
 
     it('calls correct url', () => {
       const url = '/savedqueryviewapi/api/create';
-      actions.saveQuery(query);
+      const thunk = actions.saveQuery(query);
+      thunk((/* mockDispatch */) => {});
       expect(ajaxStub.getCall(0).args[0].url).to.equal(url);
     });
   });
diff --git a/superset/assets/spec/javascripts/sqllab/fixtures.js 
b/superset/assets/spec/javascripts/sqllab/fixtures.js
index c05a745..510b5d5 100644
--- a/superset/assets/spec/javascripts/sqllab/fixtures.js
+++ b/superset/assets/spec/javascripts/sqllab/fixtures.js
@@ -319,15 +319,18 @@ export const runningQuery = {
 export const cachedQuery = Object.assign({}, queries[0], { cached: true });
 
 export const initialState = {
-  alerts: [],
-  queries: {},
-  databases: {},
-  queryEditors: [defaultQueryEditor],
-  tabHistory: [defaultQueryEditor.id],
-  tables: [],
-  workspaceQueries: [],
-  queriesLastUpdate: 0,
-  activeSouthPaneTab: 'Results',
+  sqlLab: {
+    alerts: [],
+    queries: {},
+    databases: {},
+    queryEditors: [defaultQueryEditor],
+    tabHistory: [defaultQueryEditor.id],
+    tables: [],
+    workspaceQueries: [],
+    queriesLastUpdate: 0,
+    activeSouthPaneTab: 'Results',
+  },
+  messageToasts: [],
 };
 
 export const query = {
diff --git a/superset/assets/spec/javascripts/sqllab/reducers_spec.js 
b/superset/assets/spec/javascripts/sqllab/reducers_spec.js
index a23ceb5..2931d13 100644
--- a/superset/assets/spec/javascripts/sqllab/reducers_spec.js
+++ b/superset/assets/spec/javascripts/sqllab/reducers_spec.js
@@ -3,12 +3,17 @@ import { expect } from 'chai';
 
 import * as r from '../../../src/SqlLab/reducers';
 import * as actions from '../../../src/SqlLab/actions';
-import { alert, table, initialState } from './fixtures';
+import { table, initialState as mockState } from './fixtures';
+
+const initialState = mockState.sqlLab;
 
 describe('sqlLabReducer', () => {
   describe('CLONE_QUERY_TO_NEW_TAB', () => {
     const testQuery = { sql: 'SELECT * FROM...', dbId: 1, id: 'flasj233' };
-    let newState = Object.assign({}, initialState, { queries: { 
[testQuery.id]: testQuery } });
+    let newState = {
+      ...initialState,
+      queries: { [testQuery.id]: testQuery },
+    };
     beforeEach(() => {
       newState = r.sqlLabReducer(newState, 
actions.cloneQueryToNewTab(testQuery));
     });
@@ -29,24 +34,12 @@ describe('sqlLabReducer', () => {
       expect(newState.tabHistory[1]).to.eq(newState.queryEditors[1].id);
     });
   });
-  describe('Alerts', () => {
-    const state = Object.assign({}, initialState);
-    let newState;
-    it('should add one alert', () => {
-      newState = r.sqlLabReducer(state, actions.addAlert(alert));
-      expect(newState.alerts).to.have.lengthOf(1);
-    });
-    it('should remove one alert', () => {
-      newState = r.sqlLabReducer(newState, 
actions.removeAlert(newState.alerts[0]));
-      expect(newState.alerts).to.have.lengthOf(0);
-    });
-  });
   describe('Query editors actions', () => {
     let newState;
     let defaultQueryEditor;
     let qe;
     beforeEach(() => {
-      newState = Object.assign({}, initialState);
+      newState = { ...initialState };
       defaultQueryEditor = newState.queryEditors[0];
       qe = Object.assign({}, defaultQueryEditor);
       newState = r.sqlLabReducer(newState, actions.addQueryEditor(qe));
@@ -134,8 +127,8 @@ describe('sqlLabReducer', () => {
     let query;
     let newQuery;
     beforeEach(() => {
-      newState = Object.assign({}, initialState);
-      newQuery = Object.assign({}, query);
+      newState = { ...initialState };
+      newQuery = { ...query };
     });
     it('should start a query', () => {
       newState = r.sqlLabReducer(newState, actions.startQuery(newQuery));
diff --git a/superset/assets/src/SqlLab/actions.js 
b/superset/assets/src/SqlLab/actions.js
index 540bfe7..58db1a7 100644
--- a/superset/assets/src/SqlLab/actions.js
+++ b/superset/assets/src/SqlLab/actions.js
@@ -1,11 +1,16 @@
-/* global notify */
+/* global window */
+/* eslint no-undef: 2 */
+import $ from 'jquery';
 import shortid from 'shortid';
 import { now } from '../modules/dates';
 import { t } from '../locales';
+import {
+  addSuccessToast as addSuccessToastAction,
+  addDangerToast as addDangerToastAction,
+  addInfoToast as addInfoToastAction,
+} from '../messageToasts/actions';
 import { COMMON_ERR_MESSAGES } from '../common';
 
-const $ = require('jquery');
-
 export const RESET_STATE = 'RESET_STATE';
 export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
 export const CLONE_QUERY_TO_NEW_TAB = 'CLONE_QUERY_TO_NEW_TAB';
@@ -28,8 +33,6 @@ export const QUERY_EDITOR_PERSIST_HEIGHT = 
'QUERY_EDITOR_PERSIST_HEIGHT';
 export const SET_DATABASES = 'SET_DATABASES';
 export const SET_ACTIVE_QUERY_EDITOR = 'SET_ACTIVE_QUERY_EDITOR';
 export const SET_ACTIVE_SOUTHPANE_TAB = 'SET_ACTIVE_SOUTHPANE_TAB';
-export const ADD_ALERT = 'ADD_ALERT';
-export const REMOVE_ALERT = 'REMOVE_ALERT';
 export const REFRESH_QUERIES = 'REFRESH_QUERIES';
 export const RUN_QUERY = 'RUN_QUERY';
 export const START_QUERY = 'START_QUERY';
@@ -46,21 +49,31 @@ export const CREATE_DATASOURCE_STARTED = 
'CREATE_DATASOURCE_STARTED';
 export const CREATE_DATASOURCE_SUCCESS = 'CREATE_DATASOURCE_SUCCESS';
 export const CREATE_DATASOURCE_FAILED = 'CREATE_DATASOURCE_FAILED';
 
+export const addInfoToast = addInfoToastAction;
+export const addSuccessToast = addSuccessToastAction;
+export const addDangerToast = addDangerToastAction;
+
 export function resetState() {
   return { type: RESET_STATE };
 }
 
 export function saveQuery(query) {
-  const url = '/savedqueryviewapi/api/create';
-  $.ajax({
-    type: 'POST',
-    url,
-    data: query,
-    success: () => notify.success(t('Your query was saved')),
-    error: () => notify.error(t('Your query could not be saved')),
-    dataType: 'json',
-  });
-  return { type: SAVE_QUERY };
+  return (dispatch) => {
+    const url = '/savedqueryviewapi/api/create';
+    $.ajax({
+      type: 'POST',
+      url,
+      data: query,
+      success: () => {
+        dispatch(addSuccessToast(t('Your query was saved')));
+      },
+      error: () => {
+        dispatch(addDangerToast(t('Your query could not be saved')));
+      },
+      dataType: 'json',
+    });
+    return { type: SAVE_QUERY };
+  };
 }
 
 export function startQuery(query) {
@@ -144,7 +157,7 @@ export function runQuery(query) {
       select_as_cta: query.ctas,
       templateParams: query.templateParams,
     };
-    const sqlJsonUrl = '/superset/sql_json/' + location.search;
+    const sqlJsonUrl = '/superset/sql_json/' + window.location.search;
     $.ajax({
       type: 'POST',
       dataType: 'json',
@@ -191,10 +204,10 @@ export function postStopQuery(query) {
       url: stopQueryUrl,
       data: stopQueryRequestData,
       success() {
-        notify.success(t('Query was stopped.'));
+        dispatch(addSuccessToast(t('Query was stopped.')));
       },
       error() {
-        notify.error(t('Failed at stopping query.'));
+        dispatch(addDangerToast(t('Failed at stopping query.')));
       },
     });
   };
@@ -216,16 +229,6 @@ export function cloneQueryToNewTab(query) {
   return { type: CLONE_QUERY_TO_NEW_TAB, query };
 }
 
-export function addAlert(alert) {
-  const o = Object.assign({}, alert);
-  o.id = shortid.generate();
-  return { type: ADD_ALERT, alert: o };
-}
-
-export function removeAlert(alert) {
-  return { type: REMOVE_ALERT, alert };
-}
-
 export function setActiveQueryEditor(queryEditor) {
   return { type: SET_ACTIVE_QUERY_EDITOR, queryEditor };
 }
@@ -314,7 +317,7 @@ export function addTable(query, tableName, schemaName) {
         isMetadataLoading: false,
       });
       dispatch(mergeTable(newTable));
-      notify.error(t('Error occurred while fetching table metadata'));
+      dispatch(addDangerToast(t('Error occurred while fetching table 
metadata')));
     });
 
     url = 
`/superset/extra_table_metadata/${query.dbId}/${tableName}/${schemaName}/`;
@@ -327,7 +330,7 @@ export function addTable(query, tableName, schemaName) {
         isExtraMetadataLoading: false,
       });
       dispatch(mergeTable(newTable));
-      notify.error(t('Error occurred while fetching table metadata'));
+      dispatch(addDangerToast(t('Error occurred while fetching table 
metadata')));
     });
   };
 }
@@ -389,7 +392,9 @@ export function popStoredQuery(urlId) {
         };
         dispatch(addQueryEditor(queryEditorProps));
       },
-      error: () => notify.error(t('The query couldn\'t be loaded')),
+      error: () => {
+        dispatch(addDangerToast(t('The query couldn\'t be loaded')));
+      },
     });
   };
 }
@@ -409,7 +414,9 @@ export function popSavedQuery(saveQueryId) {
         };
         dispatch(addQueryEditor(queryEditorProps));
       },
-      error: () => notify.error(t('The query couldn\'t be loaded')),
+      error: () => {
+        dispatch(addDangerToast(t('The query couldn\'t be loaded')));
+      },
     });
   };
 }
diff --git a/superset/assets/src/SqlLab/components/App.jsx 
b/superset/assets/src/SqlLab/components/App.jsx
index 3698a2a..8a0c084 100644
--- a/superset/assets/src/SqlLab/components/App.jsx
+++ b/superset/assets/src/SqlLab/components/App.jsx
@@ -2,15 +2,14 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
+import $ from 'jquery';
 
 import TabbedSqlEditors from './TabbedSqlEditors';
 import QueryAutoRefresh from './QueryAutoRefresh';
 import QuerySearch from './QuerySearch';
-import AlertsWrapper from '../../components/AlertsWrapper';
+import ToastPresenter from '../../messageToasts/containers/ToastPresenter';
 import * as Actions from '../actions';
 
-const $ = window.$ = require('jquery');
-
 class App extends React.PureComponent {
   constructor(props) {
     super(props);
@@ -39,8 +38,10 @@ class App extends React.PureComponent {
     const alertEl = $('#sqllab-alerts');
     const headerEl = $('header .navbar');
     const headerHeight = headerEl.outerHeight() + 
parseInt(headerEl.css('marginBottom'), 10);
-    const searchHeaderHeight = searchHeaderEl.length > 0 ?
-      searchHeaderEl.outerHeight() + 
parseInt(searchHeaderEl.css('marginBottom'), 10) : 0;
+    const searchHeaderHeight =
+      searchHeaderEl.length > 0
+        ? searchHeaderEl.outerHeight() + 
parseInt(searchHeaderEl.css('marginBottom'), 10)
+        : 0;
     const tabsHeight = tabsEl.length > 0 ? tabsEl.outerHeight() : 
searchHeaderHeight;
     const warningHeight = warningEl.length > 0 ? warningEl.outerHeight() : 0;
     const alertHeight = alertEl.length > 0 ? alertEl.outerHeight() : 0;
@@ -71,27 +72,17 @@ class App extends React.PureComponent {
     }
     return (
       <div className="App SqlLab">
-        <AlertsWrapper initMessages={this.props.initMessages} />
-        <div className="container-fluid">
-          {content}
-        </div>
+        <div className="container-fluid">{content}</div>
+        <ToastPresenter />
       </div>
     );
   }
 }
 
 App.propTypes = {
-  alerts: PropTypes.array,
   actions: PropTypes.object,
-  initMessages: PropTypes.array,
 };
 
-function mapStateToProps(state) {
-  return {
-    alerts: state.alerts,
-    initMessages: state.flash_messages,
-  };
-}
 function mapDispatchToProps(dispatch) {
   return {
     actions: bindActionCreators(Actions, dispatch),
@@ -99,4 +90,7 @@ function mapDispatchToProps(dispatch) {
 }
 
 export { App };
-export default connect(mapStateToProps, mapDispatchToProps)(App);
+export default connect(
+  null,
+  mapDispatchToProps,
+)(App);
diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx 
b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
index 55e06cc..4bd034e 100644
--- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
+++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx
@@ -57,10 +57,10 @@ QueryAutoRefresh.propTypes = {
   queriesLastUpdate: PropTypes.number.isRequired,
 };
 
-function mapStateToProps(state) {
+function mapStateToProps({ sqlLab }) {
   return {
-    queries: state.queries,
-    queriesLastUpdate: state.queriesLastUpdate,
+    queries: sqlLab.queries,
+    queriesLastUpdate: sqlLab.queriesLastUpdate,
   };
 }
 
diff --git a/superset/assets/src/SqlLab/components/QuerySearch.jsx 
b/superset/assets/src/SqlLab/components/QuerySearch.jsx
index e6a19d9..d13d993 100644
--- a/superset/assets/src/SqlLab/components/QuerySearch.jsx
+++ b/superset/assets/src/SqlLab/components/QuerySearch.jsx
@@ -1,3 +1,4 @@
+/* eslint no-undef: 2 */
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Button } from 'react-bootstrap';
@@ -14,7 +15,7 @@ import { STATUS_OPTIONS, TIME_OPTIONS } from '../constants';
 import AsyncSelect from '../../components/AsyncSelect';
 import { t } from '../../locales';
 
-const $ = (window.$ = require('jquery'));
+const $ = require('jquery');
 
 const propTypes = {
   actions: PropTypes.object.isRequired,
@@ -127,10 +128,7 @@ class QuerySearch extends React.PureComponent {
     const options = data.result.map(db => ({ value: db.id, label: 
db.database_name }));
     this.props.actions.setDatabases(data.result);
     if (data.result.length === 0) {
-      this.props.actions.addAlert({
-        bsStyle: 'danger',
-        msg: t("It seems you don't have access to any database"),
-      });
+      this.props.actions.addDangerToast(t("It seems you don't have access to 
any database"));
     }
     return options;
   }
diff --git a/superset/assets/src/SqlLab/components/SouthPane.jsx 
b/superset/assets/src/SqlLab/components/SouthPane.jsx
index 7102880..73ba069 100644
--- a/superset/assets/src/SqlLab/components/SouthPane.jsx
+++ b/superset/assets/src/SqlLab/components/SouthPane.jsx
@@ -97,9 +97,9 @@ class SouthPane extends React.PureComponent {
   }
 }
 
-function mapStateToProps(state) {
+function mapStateToProps({ sqlLab }) {
   return {
-    activeSouthPaneTab: state.activeSouthPaneTab,
+    activeSouthPaneTab: sqlLab.activeSouthPaneTab,
   };
 }
 
diff --git a/superset/assets/src/SqlLab/components/SqlEditor.jsx 
b/superset/assets/src/SqlLab/components/SqlEditor.jsx
index 37626a8..a4cb4eb 100644
--- a/superset/assets/src/SqlLab/components/SqlEditor.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditor.jsx
@@ -1,3 +1,5 @@
+/* global window */
+/* eslint no-undef: 2 */
 import React from 'react';
 import PropTypes from 'prop-types';
 import throttle from 'lodash.throttle';
@@ -126,7 +128,7 @@ class SqlEditor extends React.PureComponent {
     this.props.actions.queryEditorSetSql(this.props.queryEditor, sql);
   }
   runQuery() {
-    this.startQuery(!this.props.database.allow_run_sync);
+    this.startQuery(!(this.props.database || {}).allow_run_sync);
   }
   startQuery(runAsync = false, ctas = false) {
     const qe = this.props.queryEditor;
diff --git a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx 
b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
index 08c0e9c..a255ca6 100644
--- a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
@@ -1,4 +1,5 @@
-/* global notify */
+/* global window */
+/* eslint no-undef: 2 */
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Button } from 'react-bootstrap';
@@ -9,7 +10,7 @@ import TableElement from './TableElement';
 import AsyncSelect from '../../components/AsyncSelect';
 import { t } from '../../locales';
 
-const $ = window.$ = require('jquery');
+const $ = require('jquery');
 
 const propTypes = {
   queryEditor: PropTypes.object.isRequired,
@@ -62,10 +63,7 @@ class SqlEditorLeftBar extends React.PureComponent {
     const options = data.result.map(db => ({ value: db.id, label: 
db.database_name }));
     this.props.actions.setDatabases(data.result);
     if (data.result.length === 0) {
-      this.props.actions.addAlert({
-        bsStyle: 'danger',
-        msg: t('It seems you don\'t have access to any database'),
-      });
+      this.props.actions.addDangerToast(t('It seems you don\'t have access to 
any database'));
     }
     return options;
   }
@@ -88,7 +86,7 @@ class SqlEditorLeftBar extends React.PureComponent {
       })
       .fail(() => {
         this.setState({ tableLoading: false, tableOptions: [], tableLength: 0 
});
-        notify.error(t('Error while fetching table list'));
+        this.props.actions.addDangerToast(t('Error while fetching table 
list'));
       });
     } else {
       this.setState({ tableLoading: false, tableOptions: [], filterOptions: 
null });
@@ -129,7 +127,7 @@ class SqlEditorLeftBar extends React.PureComponent {
       })
       .fail(() => {
         this.setState({ schemaLoading: false, schemaOptions: [] });
-        notify.error(t('Error while fetching schema list'));
+        this.props.actions.addDangerToast(t('Error while fetching schema 
list'));
       });
     }
   }
@@ -159,7 +157,9 @@ class SqlEditorLeftBar extends React.PureComponent {
               '_od_DatabaseAsync=asc'
             }
             onChange={this.onDatabaseChange.bind(this)}
-            onAsyncError={() => notify.error(t('Error while fetching database 
list'))}
+            onAsyncError={() => {
+              this.props.actions.addDangerToast(t('Error while fetching 
database list'));
+            }}
             value={this.props.queryEditor.dbId}
             databaseId={this.props.queryEditor.dbId}
             actions={this.props.actions}
diff --git a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx 
b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
index b9acc16..0c5b272 100644
--- a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -231,14 +231,14 @@ class TabbedSqlEditors extends React.PureComponent {
 TabbedSqlEditors.propTypes = propTypes;
 TabbedSqlEditors.defaultProps = defaultProps;
 
-function mapStateToProps(state) {
+function mapStateToProps({ sqlLab }) {
   return {
-    databases: state.databases,
-    queryEditors: state.queryEditors,
-    queries: state.queries,
-    tabHistory: state.tabHistory,
-    tables: state.tables,
-    defaultDbId: state.defaultDbId,
+    databases: sqlLab.databases,
+    queryEditors: sqlLab.queryEditors,
+    queries: sqlLab.queries,
+    tabHistory: sqlLab.tabHistory,
+    tables: sqlLab.tables,
+    defaultDbId: sqlLab.defaultDbId,
   };
 }
 function mapDispatchToProps(dispatch) {
diff --git a/superset/assets/src/SqlLab/components/VisualizeModal.jsx 
b/superset/assets/src/SqlLab/components/VisualizeModal.jsx
index 14ba0c0..c02656e 100644
--- a/superset/assets/src/SqlLab/components/VisualizeModal.jsx
+++ b/superset/assets/src/SqlLab/components/VisualizeModal.jsx
@@ -1,4 +1,4 @@
-/* global notify */
+/* eslint no-undef: 2 */
 import moment from 'moment';
 import React from 'react';
 import PropTypes from 'prop-types';
@@ -168,13 +168,13 @@ class VisualizeModal extends React.PureComponent {
         if (mainGroupBy) {
           formData.groupby = [mainGroupBy.name];
         }
-        notify.info(t('Creating a data source and popping a new tab'));
+        this.props.actions.addInfoToast(t('Creating a data source and creating 
a new tab'));
 
         // open new window for data visualization
         exportChart(formData);
       })
       .fail(() => {
-        notify.error(this.props.errorMessage);
+        this.props.actions.addDangerToast(this.props.errorMessage);
       });
   }
   changeDatasourceName(event) {
@@ -295,11 +295,11 @@ class VisualizeModal extends React.PureComponent {
 VisualizeModal.propTypes = propTypes;
 VisualizeModal.defaultProps = defaultProps;
 
-function mapStateToProps(state) {
+function mapStateToProps({ sqlLab }) {
   return {
-    datasource: state.datasource,
-    errorMessage: state.errorMessage,
-    timeout: state.common ? state.common.conf.SUPERSET_WEBSERVER_TIMEOUT : 
null,
+    datasource: sqlLab.datasource,
+    errorMessage: sqlLab.errorMessage,
+    timeout: sqlLab.common ? sqlLab.common.conf.SUPERSET_WEBSERVER_TIMEOUT : 
null,
   };
 }
 
diff --git a/superset/assets/src/SqlLab/getInitialState.js 
b/superset/assets/src/SqlLab/getInitialState.js
new file mode 100644
index 0000000..9452ac5
--- /dev/null
+++ b/superset/assets/src/SqlLab/getInitialState.js
@@ -0,0 +1,33 @@
+/* eslint no-undef: 2 */
+import shortid from 'shortid';
+import { t } from '../locales';
+import getToastsFromPyFlashMessages from 
'../messageToasts/utils/getToastsFromPyFlashMessages';
+
+export default function getInitialState({ defaultDbId, ...restBootstrapData }) 
{
+  const defaultQueryEditor = {
+    id: shortid.generate(),
+    title: t('Untitled Query'),
+    sql: 'SELECT *\nFROM\nWHERE',
+    selectedText: null,
+    latestQueryId: null,
+    autorun: false,
+    dbId: defaultDbId,
+  };
+
+  return {
+    sqlLab: {
+      alerts: [],
+      queries: {},
+      databases: {},
+      queryEditors: [defaultQueryEditor],
+      tabHistory: [defaultQueryEditor.id],
+      tables: [],
+      queriesLastUpdate: 0,
+      activeSouthPaneTab: 'Results',
+      ...restBootstrapData,
+    },
+    messageToasts: getToastsFromPyFlashMessages(
+      (restBootstrapData.common || {}).flash_messages || [],
+    ),
+  };
+}
diff --git a/superset/assets/src/SqlLab/index.jsx 
b/superset/assets/src/SqlLab/index.jsx
index 4e2eae8..24983de 100644
--- a/superset/assets/src/SqlLab/index.jsx
+++ b/superset/assets/src/SqlLab/index.jsx
@@ -4,7 +4,8 @@ import { createStore, compose, applyMiddleware } from 'redux';
 import { Provider } from 'react-redux';
 import thunkMiddleware from 'redux-thunk';
 
-import { getInitialState, sqlLabReducer } from './reducers';
+import getInitialState from './getInitialState';
+import rootReducer from './reducers';
 import { initEnhancer } from '../reduxUtils';
 import { initJQueryAjax } from '../modules/utils';
 import App from './components/App';
@@ -19,13 +20,21 @@ initJQueryAjax();
 
 const appContainer = document.getElementById('app');
 const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
-const state = Object.assign({}, getInitialState(bootstrapData.defaultDbId), 
bootstrapData);
+const state = getInitialState(bootstrapData);
 
 const store = createStore(
-  sqlLabReducer, state, compose(applyMiddleware(thunkMiddleware), 
initEnhancer()));
+  rootReducer,
+  state,
+  compose(
+    applyMiddleware(thunkMiddleware),
+    initEnhancer(),
+  ),
+);
 
 // jquery hack to highlight the navbar menu
-$('a:contains("SQL Lab")').parent().addClass('active');
+$('a:contains("SQL Lab")')
+  .parent()
+  .addClass('active');
 
 render(
   <Provider store={store}>
diff --git a/superset/assets/src/SqlLab/reducers.js 
b/superset/assets/src/SqlLab/reducers.js
index 690126d..a55a022 100644
--- a/superset/assets/src/SqlLab/reducers.js
+++ b/superset/assets/src/SqlLab/reducers.js
@@ -1,34 +1,20 @@
+import { combineReducers } from 'redux';
 import shortid from 'shortid';
+import messageToasts from '../messageToasts/reducers';
+
 import * as actions from './actions';
 import { now } from '../modules/dates';
-import { addToObject, alterInObject, alterInArr, removeFromArr, getFromArr, 
addToArr }
-  from '../reduxUtils';
+import {
+  addToObject,
+  alterInObject,
+  alterInArr,
+  removeFromArr,
+  getFromArr,
+  addToArr,
+} from '../reduxUtils';
 import { t } from '../locales';
 
-export function getInitialState(defaultDbId) {
-  const defaultQueryEditor = {
-    id: shortid.generate(),
-    title: t('Untitled Query'),
-    sql: 'SELECT *\nFROM\nWHERE',
-    selectedText: null,
-    latestQueryId: null,
-    autorun: false,
-    dbId: defaultDbId,
-  };
-
-  return {
-    alerts: [],
-    queries: {},
-    databases: {},
-    queryEditors: [defaultQueryEditor],
-    tabHistory: [defaultQueryEditor.id],
-    tables: [],
-    queriesLastUpdate: 0,
-    activeSouthPaneTab: 'Results',
-  };
-}
-
-export const sqlLabReducer = function (state, action) {
+export const sqlLabReducer = function (state = {}, action) {
   const actionHandlers = {
     [actions.ADD_QUERY_EDITOR]() {
       const tabHistory = state.tabHistory.slice();
@@ -225,9 +211,6 @@ export const sqlLabReducer = function (state, action) {
     [actions.QUERY_EDITOR_PERSIST_HEIGHT]() {
       return alterInArr(state, 'queryEditors', action.queryEditor, { height: 
action.currentHeight });
     },
-    [actions.ADD_ALERT]() {
-      return addToArr(state, 'alerts', action.alert);
-    },
     [actions.SET_DATABASES]() {
       const databases = {};
       action.databases.forEach((db) => {
@@ -235,9 +218,6 @@ export const sqlLabReducer = function (state, action) {
       });
       return Object.assign({}, state, { databases });
     },
-    [actions.REMOVE_ALERT]() {
-      return removeFromArr(state, 'alerts', action.alert);
-    },
     [actions.REFRESH_QUERIES]() {
       let newQueries = Object.assign({}, state.queries);
       // Fetch the updates to the queries present in the store.
@@ -284,3 +264,8 @@ export const sqlLabReducer = function (state, action) {
   }
   return state;
 };
+
+export default combineReducers({
+  sqlLab: sqlLabReducer,
+  messageToasts,
+});
diff --git a/superset/assets/src/chart/Chart.jsx 
b/superset/assets/src/chart/Chart.jsx
index 1718fc7..fa6d9e6 100644
--- a/superset/assets/src/chart/Chart.jsx
+++ b/superset/assets/src/chart/Chart.jsx
@@ -238,7 +238,9 @@ class Chart extends React.PureComponent {
               vizType={this.props.vizType}
               height={this.height}
               width={this.width}
-              faded={this.props.refreshOverlayVisible && 
!this.props.errorMessage}
+              faded={
+                this.props.refreshOverlayVisible && !this.props.errorMessage
+              }
               ref={(inner) => {
                 this.container = inner;
               }}
diff --git a/superset/assets/src/components/AlertsWrapper.jsx 
b/superset/assets/src/components/AlertsWrapper.jsx
deleted file mode 100644
index 672c56d..0000000
--- a/superset/assets/src/components/AlertsWrapper.jsx
+++ /dev/null
@@ -1,38 +0,0 @@
-/* global notify */
-import React from 'react';
-import AlertContainer from 'react-alert';
-import PropTypes from 'prop-types';
-
-const propTypes = {
-  initMessages: PropTypes.array,
-};
-const defaultProps = {
-  initMessages: [],
-};
-
-export default class AlertsWrapper extends React.PureComponent {
-  componentDidMount() {
-    this.props.initMessages.forEach((msg) => {
-      if (['info', 'error', 'success'].indexOf(msg[0]) >= 0) {
-        notify[msg[0]](msg[1]);
-      } else {
-        notify.show(msg[1]);
-      }
-    });
-  }
-  render() {
-    return (
-      <AlertContainer
-        ref={(ref) => {
-          global.notify = ref;
-        }}
-        offset={14}
-        position="top right"
-        theme="dark"
-        time={5000}
-        transition="fade"
-      />);
-  }
-}
-AlertsWrapper.propTypes = propTypes;
-AlertsWrapper.defaultProps = defaultProps;
diff --git a/superset/assets/src/components/URLShortLinkButton.jsx 
b/superset/assets/src/components/URLShortLinkButton.jsx
index aa9ae96..1efd4f7 100644
--- a/superset/assets/src/components/URLShortLinkButton.jsx
+++ b/superset/assets/src/components/URLShortLinkButton.jsx
@@ -4,19 +4,22 @@ import { Popover, OverlayTrigger } from 'react-bootstrap';
 import CopyToClipboard from './CopyToClipboard';
 import { getShortUrl } from '../utils/common';
 import { t } from '../locales';
+import withToasts from '../messageToasts/enhancers/withToasts';
 
 const propTypes = {
   url: PropTypes.string,
   emailSubject: PropTypes.string,
   emailContent: PropTypes.string,
+  addDangerToast: PropTypes.func.isRequired,
 };
 
-export default class URLShortLinkButton extends React.Component {
+class URLShortLinkButton extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       shortUrl: '',
     };
+    this.onShortUrlSuccess = this.onShortUrlSuccess.bind(this);
   }
 
   onShortUrlSuccess(data) {
@@ -26,7 +29,7 @@ export default class URLShortLinkButton extends 
React.Component {
   }
 
   getCopyUrl() {
-    getShortUrl(this.props.url, this.onShortUrlSuccess.bind(this));
+    getShortUrl(this.props.url, this.onShortUrlSuccess, 
this.props.addDangerToast);
   }
 
   renderPopover() {
@@ -69,3 +72,5 @@ URLShortLinkButton.defaultProps = {
 };
 
 URLShortLinkButton.propTypes = propTypes;
+
+export default withToasts(URLShortLinkButton);
diff --git a/superset/assets/src/dashboard/actions/dashboardLayout.js 
b/superset/assets/src/dashboard/actions/dashboardLayout.js
index bd01146..149ead7 100644
--- a/superset/assets/src/dashboard/actions/dashboardLayout.js
+++ b/superset/assets/src/dashboard/actions/dashboardLayout.js
@@ -1,6 +1,6 @@
 import { ActionCreators as UndoActionCreators } from 'redux-undo';
 
-import { addInfoToast } from './messageToasts';
+import { addInfoToast } from '../../messageToasts/actions';
 import { setUnsavedChanges } from './dashboardState';
 import { TABS_TYPE, ROW_TYPE } from '../util/componentTypes';
 import {
diff --git a/superset/assets/src/dashboard/actions/dashboardState.js 
b/superset/assets/src/dashboard/actions/dashboardState.js
index 5c92ff2..17f6d46 100644
--- a/superset/assets/src/dashboard/actions/dashboardState.js
+++ b/superset/assets/src/dashboard/actions/dashboardState.js
@@ -19,7 +19,7 @@ import {
   addSuccessToast,
   addWarningToast,
   addDangerToast,
-} from './messageToasts';
+} from '../../messageToasts/actions';
 
 export const SET_UNSAVED_CHANGES = 'SET_UNSAVED_CHANGES';
 export function setUnsavedChanges(hasUnsavedChanges) {
diff --git a/superset/assets/src/dashboard/components/Dashboard.jsx 
b/superset/assets/src/dashboard/components/Dashboard.jsx
index 5f5479e..80d4bdf 100644
--- a/superset/assets/src/dashboard/components/Dashboard.jsx
+++ b/superset/assets/src/dashboard/components/Dashboard.jsx
@@ -2,7 +2,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import AlertsWrapper from '../../components/AlertsWrapper';
 import getChartIdsFromLayout from '../util/getChartIdsFromLayout';
 import DashboardBuilder from '../containers/DashboardBuilder';
 import {
@@ -220,12 +219,7 @@ class Dashboard extends React.PureComponent {
   }
 
   render() {
-    return (
-      <div>
-        <AlertsWrapper initMessages={this.props.initMessages} />
-        <DashboardBuilder />
-      </div>
-    );
+    return <DashboardBuilder />;
   }
 }
 
diff --git a/superset/assets/src/dashboard/components/DashboardBuilder.jsx 
b/superset/assets/src/dashboard/components/DashboardBuilder.jsx
index 9621a49..ecb528d 100644
--- a/superset/assets/src/dashboard/components/DashboardBuilder.jsx
+++ b/superset/assets/src/dashboard/components/DashboardBuilder.jsx
@@ -14,7 +14,7 @@ import DashboardGrid from '../containers/DashboardGrid';
 import IconButton from './IconButton';
 import DragDroppable from './dnd/DragDroppable';
 import DashboardComponent from '../containers/DashboardComponent';
-import ToastPresenter from '../containers/ToastPresenter';
+import ToastPresenter from '../../messageToasts/containers/ToastPresenter';
 import WithPopoverMenu from './menu/WithPopoverMenu';
 
 import getDragDropManager from '../util/getDragDropManager';
diff --git a/superset/assets/src/dashboard/containers/DashboardHeader.jsx 
b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
index dec97b7..3740404 100644
--- a/superset/assets/src/dashboard/containers/DashboardHeader.jsx
+++ b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
@@ -23,7 +23,7 @@ import {
   updateDashboardTitle,
 } from '../actions/dashboardLayout';
 
-import { addSuccessToast, addDangerToast } from '../actions/messageToasts';
+import { addSuccessToast, addDangerToast } from '../../messageToasts/actions';
 
 import { DASHBOARD_HEADER_ID } from '../util/constants';
 
diff --git a/superset/assets/src/dashboard/deprecated/v1/actions.js 
b/superset/assets/src/dashboard/deprecated/v1/actions.js
index 7381486..a870120 100644
--- a/superset/assets/src/dashboard/deprecated/v1/actions.js
+++ b/superset/assets/src/dashboard/deprecated/v1/actions.js
@@ -1,6 +1,7 @@
-/* global notify */
+/* global window */
 import $ from 'jquery';
 import { getExploreUrlAndPayload } from '../../../explore/exploreUtils';
+import { addSuccessToast, addDangerToast } from 
'../../../messageToasts/actions';
 
 export const ADD_FILTER = 'ADD_FILTER';
 export function addFilter(sliceId, col, vals, merge = true, refresh = true) {
@@ -36,10 +37,10 @@ export function addSlicesToDashboard(dashboardId, sliceIds) 
{
         data: JSON.stringify({ slice_ids: sliceIds }),
       },
     })
-      .done(() => {
-        // Refresh page to allow for slices to re-render
-        window.location.reload();
-      })
+    .done(() => {
+      // Refresh page to allow for slices to re-render
+      window.location.reload();
+    })
   );
 }
 
@@ -75,13 +76,13 @@ export function saveSlice(slice, sliceName) {
       },
       success: () => {
         dispatch(updateSliceName(slice, sliceName));
-        notify.success('This slice name was saved successfully.');
+        dispatch(addSuccessToast('This slice name was saved successfully.'));
       },
       error: () => {
         // if server-side reject the overwrite action,
         // revert to old state
         dispatch(updateSliceName(slice, oldName));
-        notify.error("You don't have the rights to alter this slice");
+        dispatch(addDangerToast("You don't have the rights to alter this 
slice"));
       },
     });
   };
diff --git 
a/superset/assets/src/dashboard/deprecated/v1/components/Dashboard.jsx 
b/superset/assets/src/dashboard/deprecated/v1/components/Dashboard.jsx
index ec831fa..b9e6240 100644
--- a/superset/assets/src/dashboard/deprecated/v1/components/Dashboard.jsx
+++ b/superset/assets/src/dashboard/deprecated/v1/components/Dashboard.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import AlertsWrapper from '../../../../components/AlertsWrapper';
+import ToastsPresenter from 
'../../../../messageToasts/containers/ToastPresenter';
 import GridLayout from './GridLayout';
 import Header from './Header';
 import { exportChart } from '../../../../explore/exploreUtils';
@@ -385,7 +385,7 @@ class Dashboard extends React.PureComponent {
     return (
       <div id="dashboard-container">
         <div id="dashboard-header">
-          <AlertsWrapper initMessages={this.props.initMessages} />
+          <ToastsPresenter />
           <Header
             dashboard={this.props.dashboard}
             unsavedChanges={this.state.unsavedChanges}
diff --git 
a/superset/assets/src/dashboard/deprecated/v1/components/SaveModal.jsx 
b/superset/assets/src/dashboard/deprecated/v1/components/SaveModal.jsx
index aa622ab..7a44156 100644
--- a/superset/assets/src/dashboard/deprecated/v1/components/SaveModal.jsx
+++ b/superset/assets/src/dashboard/deprecated/v1/components/SaveModal.jsx
@@ -1,13 +1,14 @@
-/* global notify */
+/* global window */
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Button, FormControl, FormGroup, Radio } from 'react-bootstrap';
+import $ from 'jquery';
+
 import { getAjaxErrorMsg } from '../../../../modules/utils';
 import ModalTrigger from '../../../../components/ModalTrigger';
 import { t } from '../../../../locales';
 import Checkbox from '../../../../components/Checkbox';
-
-const $ = window.$ = require('jquery');
+import withToasts from '../../../../messageToasts/enhancers/withToasts';
 
 const propTypes = {
   css: PropTypes.string,
@@ -16,6 +17,8 @@ const propTypes = {
   filters: PropTypes.object.isRequired,
   serialize: PropTypes.func,
   onSave: PropTypes.func,
+  addSuccessToast: PropTypes.func.isRequired,
+  addDangerToast: PropTypes.func.isRequired,
 };
 
 class SaveModal extends React.PureComponent {
@@ -57,19 +60,23 @@ class SaveModal extends React.PureComponent {
       data: {
         data: JSON.stringify(data),
       },
-      success(resp) {
+      success: (resp) => {
         saveModal.close();
         onSaveDashboard();
         if (saveType === 'newDashboard') {
           window.location = `/superset/dashboard/${resp.id}/`;
         } else {
-          notify.success(t('This dashboard was saved successfully.'));
+          this.props.addSuccessToast(
+            t('This dashboard was saved successfully.'),
+          );
         }
       },
-      error(error) {
+      error: (error) => {
         saveModal.close();
         const errorMsg = getAjaxErrorMsg(error);
-        notify.error(t('Sorry, there was an error saving this dashboard: ') + 
errorMsg);
+        this.props.addDangerToast(
+          t('Sorry, there was an error saving this dashboard: ') + errorMsg,
+        );
       },
     });
   }
@@ -91,10 +98,9 @@ class SaveModal extends React.PureComponent {
     } else if (saveType === 'newDashboard') {
       if (!newDashboardTitle) {
         this.modal.close();
-        showModal({
-          title: t('Error'),
-          body: t('You must pick a name for the new dashboard'),
-        });
+        this.props.addDangerToast(
+          t('You must pick a name for the new dashboard'),
+        );
       } else {
         data.dashboard_title = newDashboardTitle;
         url = `/superset/copy_dash/${dashboard.id}/`;
@@ -156,6 +162,7 @@ class SaveModal extends React.PureComponent {
     );
   }
 }
+
 SaveModal.propTypes = propTypes;
 
-export default SaveModal;
+export default withToasts(SaveModal);
diff --git a/superset/assets/src/dashboard/deprecated/v1/index.jsx 
b/superset/assets/src/dashboard/deprecated/v1/index.jsx
index d7e898e..47d1e24 100644
--- a/superset/assets/src/dashboard/deprecated/v1/index.jsx
+++ b/superset/assets/src/dashboard/deprecated/v1/index.jsx
@@ -15,10 +15,16 @@ initJQueryAjax();
 
 const appContainer = document.getElementById('app');
 const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
-const initState = Object.assign({}, getInitialState(bootstrapData));
+const initState = getInitialState(bootstrapData);
 
 const store = createStore(
-  rootReducer, initState, compose(applyMiddleware(thunk), 
initEnhancer(false)));
+  rootReducer,
+  initState,
+  compose(
+    applyMiddleware(thunk),
+    initEnhancer(false),
+  ),
+);
 
 ReactDOM.render(
   <Provider store={store}>
diff --git a/superset/assets/src/dashboard/deprecated/v1/reducers.js 
b/superset/assets/src/dashboard/deprecated/v1/reducers.js
index 00bf2bf..b519e2e 100644
--- a/superset/assets/src/dashboard/deprecated/v1/reducers.js
+++ b/superset/assets/src/dashboard/deprecated/v1/reducers.js
@@ -9,6 +9,7 @@ import { getParam } from '../../../modules/utils';
 import { alterInArr, removeFromArr } from '../../../reduxUtils';
 import { applyDefaultFormData } from '../../../explore/store';
 import { getColorFromScheme } from '../../../modules/colors';
+import messageToasts from '../../../messageToasts/reducers';
 
 export function getInitialState(bootstrapData) {
   const {
@@ -121,6 +122,7 @@ export function getInitialState(bootstrapData) {
       common,
       editMode,
     },
+    messageToasts: [],
   };
 }
 
@@ -269,4 +271,5 @@ export default combineReducers({
   charts,
   dashboard,
   impressionId: () => shortid.generate(),
+  messageToasts,
 });
diff --git a/superset/assets/src/dashboard/reducers/index.js 
b/superset/assets/src/dashboard/reducers/index.js
index 787cd5f..a5be96f 100644
--- a/superset/assets/src/dashboard/reducers/index.js
+++ b/superset/assets/src/dashboard/reducers/index.js
@@ -5,7 +5,7 @@ import dashboardState from './dashboardState';
 import datasources from './datasources';
 import sliceEntities from './sliceEntities';
 import dashboardLayout from '../reducers/undoableDashboardLayout';
-import messageToasts from '../reducers/messageToasts';
+import messageToasts from '../../messageToasts/reducers';
 
 const dashboardInfo = (state = {}) => state;
 const impressionId = (state = '') => state;
diff --git a/superset/assets/src/dashboard/stylesheets/index.less 
b/superset/assets/src/dashboard/stylesheets/index.less
index b69c7b0..08a0956 100644
--- a/superset/assets/src/dashboard/stylesheets/index.less
+++ b/superset/assets/src/dashboard/stylesheets/index.less
@@ -10,4 +10,3 @@
 @import './popover-menu.less';
 @import './resizable.less';
 @import './components/index.less';
-@import './toast.less';
diff --git a/superset/assets/src/dashboard/util/constants.js 
b/superset/assets/src/dashboard/util/constants.js
index bfe24cc..09d7244 100644
--- a/superset/assets/src/dashboard/util/constants.js
+++ b/superset/assets/src/dashboard/util/constants.js
@@ -33,12 +33,6 @@ export const LARGE_HEADER = 'LARGE_HEADER';
 export const BACKGROUND_WHITE = 'BACKGROUND_WHITE';
 export const BACKGROUND_TRANSPARENT = 'BACKGROUND_TRANSPARENT';
 
-// Toast types
-export const INFO_TOAST = 'INFO_TOAST';
-export const SUCCESS_TOAST = 'SUCCESS_TOAST';
-export const WARNING_TOAST = 'WARNING_TOAST';
-export const DANGER_TOAST = 'DANGER_TOAST';
-
 // undo-redo
 export const UNDO_LIMIT = 50;
 
diff --git a/superset/assets/src/dashboard/util/propShapes.jsx 
b/superset/assets/src/dashboard/util/propShapes.jsx
index f155190..3c06e14 100644
--- a/superset/assets/src/dashboard/util/propShapes.jsx
+++ b/superset/assets/src/dashboard/util/propShapes.jsx
@@ -2,12 +2,6 @@ import PropTypes from 'prop-types';
 import componentTypes from './componentTypes';
 import backgroundStyleOptions from './backgroundStyleOptions';
 import headerStyleOptions from './headerStyleOptions';
-import {
-  INFO_TOAST,
-  SUCCESS_TOAST,
-  WARNING_TOAST,
-  DANGER_TOAST,
-} from './constants';
 
 export const componentShape = PropTypes.shape({
   id: PropTypes.string.isRequired,
@@ -26,18 +20,6 @@ export const componentShape = PropTypes.shape({
   }),
 });
 
-export const toastShape = PropTypes.shape({
-  id: PropTypes.string.isRequired,
-  toastType: PropTypes.oneOf([
-    INFO_TOAST,
-    SUCCESS_TOAST,
-    WARNING_TOAST,
-    DANGER_TOAST,
-  ]).isRequired,
-  text: PropTypes.string.isRequired,
-  duration: PropTypes.number,
-});
-
 export const chartPropShape = PropTypes.shape({
   id: PropTypes.number.isRequired,
   chartAlert: PropTypes.string,
diff --git a/superset/assets/src/explore/components/MetricDefinitionOption.jsx 
b/superset/assets/src/explore/components/MetricDefinitionOption.jsx
index c275b9c..d64d3fe 100644
--- a/superset/assets/src/explore/components/MetricDefinitionOption.jsx
+++ b/superset/assets/src/explore/components/MetricDefinitionOption.jsx
@@ -7,6 +7,7 @@ import AggregateOption from './AggregateOption';
 import columnType from '../propTypes/columnType';
 import savedMetricType from '../propTypes/savedMetricType';
 import aggregateOptionType from '../propTypes/aggregateOptionType';
+import withToasts from '../../messageToasts/enhancers/withToasts';
 
 const propTypes = {
   option: PropTypes.oneOfType([
@@ -14,9 +15,10 @@ const propTypes = {
     savedMetricType,
     aggregateOptionType,
   ]).isRequired,
+  addWarningToast: PropTypes.func.isRequired,
 };
 
-export default function MetricDefinitionOption({ option }) {
+function MetricDefinitionOption({ option, addWarningToast }) {
   if (option.metric_name) {
     return (
       <MetricOption metric={option} showType />
@@ -30,7 +32,10 @@ export default function MetricDefinitionOption({ option }) {
       <AggregateOption aggregate={option} showType />
     );
   }
-  notify.error('You must supply either a saved metric, column or aggregate to 
MetricDefinitionOption');
+  addWarningToast('You must supply either a saved metric, column or aggregate 
to MetricDefinitionOption');
   return null;
 }
+
 MetricDefinitionOption.propTypes = propTypes;
+
+export default withToasts(MetricDefinitionOption);
diff --git 
a/superset/assets/src/explore/components/controls/DatasourceControl.jsx 
b/superset/assets/src/explore/components/controls/DatasourceControl.jsx
index d63d6fe..545ad10 100644
--- a/superset/assets/src/explore/components/controls/DatasourceControl.jsx
+++ b/superset/assets/src/explore/components/controls/DatasourceControl.jsx
@@ -1,4 +1,4 @@
-/* global notify */
+/* eslint no-undef: 2 */
 import React from 'react';
 import PropTypes from 'prop-types';
 import { Table } from 'reactable';
@@ -13,12 +13,15 @@ import {
   Tooltip,
   Well,
 } from 'react-bootstrap';
+import $ from 'jquery';
 
 import ControlHeader from '../ControlHeader';
 import Loading from '../../../components/Loading';
 import { t } from '../../../locales';
 import ColumnOption from '../../../components/ColumnOption';
 import MetricOption from '../../../components/MetricOption';
+import withToasts from '../../../messageToasts/enhancers/withToasts';
+
 
 const propTypes = {
   description: PropTypes.string,
@@ -27,13 +30,14 @@ const propTypes = {
   onChange: PropTypes.func,
   value: PropTypes.string.isRequired,
   datasource: PropTypes.object,
+  addDangerToast: PropTypes.func.isRequired,
 };
 
 const defaultProps = {
   onChange: () => {},
 };
 
-export default class DatasourceControl extends React.PureComponent {
+class DatasourceControl extends React.PureComponent {
   constructor(props) {
     super(props);
     this.state = {
@@ -85,7 +89,7 @@ export default class DatasourceControl extends 
React.PureComponent {
         },
         error() {
           that.setState({ loading: false });
-          notify.error(t('Something went wrong while fetching the datasource 
list'));
+          this.props.addDangerToast(t('Something went wrong while fetching the 
datasource list'));
         },
       });
     }
@@ -229,3 +233,5 @@ export default class DatasourceControl extends 
React.PureComponent {
 
 DatasourceControl.propTypes = propTypes;
 DatasourceControl.defaultProps = defaultProps;
+
+export default withToasts(DatasourceControl);
diff --git 
a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx 
b/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
index ec5a365..ef8c417 100644
--- a/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
+++ b/superset/assets/src/explore/components/controls/SelectAsyncControl.jsx
@@ -1,10 +1,12 @@
-/* global notify */
+/* eslint no-undef: 2 */
 import React from 'react';
 import PropTypes from 'prop-types';
 import Select from '../../../components/AsyncSelect';
 import ControlHeader from '../ControlHeader';
 import { t } from '../../../locales';
 
+import withToasts from '../../../messageToasts/enhancers/withToasts';
+
 const propTypes = {
   dataEndpoint: PropTypes.string.isRequired,
   multi: PropTypes.bool,
@@ -18,6 +20,7 @@ const propTypes = {
     PropTypes.arrayOf(PropTypes.string),
     PropTypes.arrayOf(PropTypes.number),
   ]),
+  addDangerToast: PropTypes.func.isRequired,
 };
 
 const defaultProps = {
@@ -40,7 +43,7 @@ const SelectAsyncControl = (props) => {
       <Select
         dataEndpoint={dataEndpoint}
         onChange={onSelectionChange}
-        onAsyncError={errorMsg => notify.error(onAsyncErrorMessage + ': ' + 
errorMsg)}
+        onAsyncError={errorMsg => 
this.props.addDangerToast(onAsyncErrorMessage + ': ' + errorMsg)}
         mutator={mutator}
         multi={multi}
         value={value}
@@ -54,4 +57,4 @@ const SelectAsyncControl = (props) => {
 SelectAsyncControl.propTypes = propTypes;
 SelectAsyncControl.defaultProps = defaultProps;
 
-export default SelectAsyncControl;
+export default withToasts(SelectAsyncControl);
diff --git a/superset/assets/src/explore/index.jsx 
b/superset/assets/src/explore/index.jsx
index 07870e4..283b5f5 100644
--- a/superset/assets/src/explore/index.jsx
+++ b/superset/assets/src/explore/index.jsx
@@ -1,4 +1,4 @@
-/* eslint camelcase: 0 */
+/* eslint no-undef: 2 */
 import React from 'react';
 import ReactDOM from 'react-dom';
 import { createStore, applyMiddleware, compose } from 'redux';
@@ -9,11 +9,12 @@ import shortid from 'shortid';
 import { now } from '../modules/dates';
 import { initEnhancer } from '../reduxUtils';
 import { getChartKey } from './exploreUtils';
-import AlertsWrapper from '../components/AlertsWrapper';
+import ToastPresenter from '../messageToasts/containers/ToastPresenter';
 import { getControlsState, getFormDataFromControls } from './store';
 import { initJQueryAjax } from '../modules/utils';
 import ExploreViewContainer from './components/ExploreViewContainer';
 import rootReducer from './reducers/index';
+import getToastsFromPyFlashMessages from 
'../messageToasts/utils/getToastsFromPyFlashMessages';
 
 import { appSetup } from '../common';
 import './main.css';
@@ -26,25 +27,24 @@ const exploreViewContainer = document.getElementById('app');
 const bootstrapData = 
JSON.parse(exploreViewContainer.getAttribute('data-bootstrap'));
 const controls = getControlsState(bootstrapData, bootstrapData.form_data);
 const rawFormData = { ...bootstrapData.form_data };
+
 delete bootstrapData.form_data;
 delete bootstrapData.common.locale;
 delete bootstrapData.common.language_pack;
 
 // Initial state
-const bootstrappedState = Object.assign(
-  bootstrapData, {
-    rawFormData,
-    controls,
-    filterColumnOpts: [],
-    isDatasourceMetaLoading: false,
-    isStarred: false,
-  },
-);
+const bootstrappedState = {
+  ...bootstrapData,
+  rawFormData,
+  controls,
+  filterColumnOpts: [],
+  isDatasourceMetaLoading: false,
+  isStarred: false,
+};
 const slice = bootstrappedState.slice;
-const sliceFormData = slice ?
-  getFormDataFromControls(getControlsState(bootstrapData, slice.form_data))
-  :
-  null;
+const sliceFormData = slice
+  ? getFormDataFromControls(getControlsState(bootstrapData, slice.form_data))
+  : null;
 const chartKey = getChartKey(bootstrappedState);
 const initState = {
   charts: {
@@ -68,16 +68,23 @@ const initState = {
   },
   explore: bootstrappedState,
   impressionId: shortid.generate(),
+  messageToasts: getToastsFromPyFlashMessages((bootstrapData.common || 
{}).flash_messages || []),
 };
-const store = createStore(rootReducer, initState,
-  compose(applyMiddleware(thunk), initEnhancer(false)),
+
+const store = createStore(
+  rootReducer,
+  initState,
+  compose(
+    applyMiddleware(thunk),
+    initEnhancer(false),
+  ),
 );
 
 ReactDOM.render(
   <Provider store={store}>
     <div>
       <ExploreViewContainer />
-      <AlertsWrapper initMessages={bootstrappedState.common.flash_messages} />
+      <ToastPresenter />
     </div>
   </Provider>,
   exploreViewContainer,
diff --git a/superset/assets/src/explore/reducers/index.js 
b/superset/assets/src/explore/reducers/index.js
index 953b0b5..461eb0f 100644
--- a/superset/assets/src/explore/reducers/index.js
+++ b/superset/assets/src/explore/reducers/index.js
@@ -3,12 +3,14 @@ import { combineReducers } from 'redux';
 import charts from '../../chart/chartReducer';
 import saveModal from './saveModalReducer';
 import explore from './exploreReducer';
+import messageToasts from '../../messageToasts/reducers';
 
-const impressionId = (state = '') => (state);
+const impressionId = (state = '') => state;
 
 export default combineReducers({
   charts,
   saveModal,
   explore,
   impressionId,
+  messageToasts,
 });
diff --git a/superset/assets/src/messageToasts/.eslintrc 
b/superset/assets/src/messageToasts/.eslintrc
new file mode 100644
index 0000000..a3f86e3
--- /dev/null
+++ b/superset/assets/src/messageToasts/.eslintrc
@@ -0,0 +1,33 @@
+{
+  "extends": "prettier",
+  "plugins": ["prettier"],
+  "rules": {
+    "prefer-template": 2,
+    "new-cap": 2,
+    "no-restricted-syntax": 2,
+    "guard-for-in": 2,
+    "prefer-arrow-callback": 2,
+    "func-names": 2,
+    "react/jsx-no-bind": 2,
+    "no-confusing-arrow": 2,
+    "jsx-a11y/no-static-element-interactions": 2,
+    "jsx-a11y/anchor-has-content": 2,
+    "react/require-default-props": 2,
+    "no-plusplus": 2,
+    "no-mixed-operators": 0,
+    "no-continue": 2,
+    "no-bitwise": 2,
+    "no-undef": 2,
+    "no-multi-assign": 2,
+    "no-restricted-properties": 2,
+    "no-prototype-builtins": 2,
+    "jsx-a11y/href-no-hash": 2,
+    "class-methods-use-this": 2,
+    "import/no-named-as-default": 2,
+    "import/prefer-default-export": 2,
+    "react/no-unescaped-entities": 2,
+    "react/no-string-refs": 2,
+    "react/jsx-indent": 0,
+    "prettier/prettier": "error"
+  }
+}
diff --git a/superset/assets/src/messageToasts/.prettierrc 
b/superset/assets/src/messageToasts/.prettierrc
new file mode 100644
index 0000000..a20502b
--- /dev/null
+++ b/superset/assets/src/messageToasts/.prettierrc
@@ -0,0 +1,4 @@
+{
+  "singleQuote": true,
+  "trailingComma": "all"
+}
diff --git a/superset/assets/src/dashboard/actions/messageToasts.js 
b/superset/assets/src/messageToasts/actions/index.js
similarity index 83%
rename from superset/assets/src/dashboard/actions/messageToasts.js
rename to superset/assets/src/messageToasts/actions/index.js
index e5c04e6..2ad888b 100644
--- a/superset/assets/src/dashboard/actions/messageToasts.js
+++ b/superset/assets/src/messageToasts/actions/index.js
@@ -5,14 +5,14 @@ import {
   SUCCESS_TOAST,
   WARNING_TOAST,
   DANGER_TOAST,
-} from '../util/constants';
+} from '../constants';
 
-function getToastUuid(type) {
+export function getToastUuid(type) {
   return `${type}-${shortid.generate()}`;
 }
 
 export const ADD_TOAST = 'ADD_TOAST';
-export function addToast({ toastType, text, duration }) {
+export function addToast({ toastType, text, duration = 8000 }) {
   return {
     type: ADD_TOAST,
     payload: {
@@ -50,10 +50,11 @@ export function addSuccessToast(text) {
 export const ADD_WARNING_TOAST = 'ADD_WARNING_TOAST';
 export function addWarningToast(text) {
   return dispatch =>
-    dispatch(addToast({ text, toastType: WARNING_TOAST, duration: 4000 }));
+    dispatch(addToast({ text, toastType: WARNING_TOAST, duration: 6000 }));
 }
 
 export const ADD_DANGER_TOAST = 'ADD_DANGER_TOAST';
 export function addDangerToast(text) {
-  return dispatch => dispatch(addToast({ text, toastType: DANGER_TOAST }));
+  return dispatch =>
+    dispatch(addToast({ text, toastType: DANGER_TOAST, duration: 8000 }));
 }
diff --git a/superset/assets/src/dashboard/components/Toast.jsx 
b/superset/assets/src/messageToasts/components/Toast.jsx
similarity index 95%
rename from superset/assets/src/dashboard/components/Toast.jsx
rename to superset/assets/src/messageToasts/components/Toast.jsx
index a2b5f0a..70cda51 100644
--- a/superset/assets/src/dashboard/components/Toast.jsx
+++ b/superset/assets/src/messageToasts/components/Toast.jsx
@@ -3,13 +3,14 @@ import cx from 'classnames';
 import PropTypes from 'prop-types';
 import React from 'react';
 
-import { toastShape } from '../util/propShapes';
+import { toastShape } from '../propShapes';
+
 import {
   INFO_TOAST,
   SUCCESS_TOAST,
   WARNING_TOAST,
   DANGER_TOAST,
-} from '../util/constants';
+} from '../constants';
 
 const propTypes = {
   toast: toastShape.isRequired,
diff --git a/superset/assets/src/dashboard/components/ToastPresenter.jsx 
b/superset/assets/src/messageToasts/components/ToastPresenter.jsx
similarity index 90%
rename from superset/assets/src/dashboard/components/ToastPresenter.jsx
rename to superset/assets/src/messageToasts/components/ToastPresenter.jsx
index 19d44b0..95c01b8 100644
--- a/superset/assets/src/dashboard/components/ToastPresenter.jsx
+++ b/superset/assets/src/messageToasts/components/ToastPresenter.jsx
@@ -2,7 +2,9 @@ import PropTypes from 'prop-types';
 import React from 'react';
 
 import Toast from './Toast';
-import { toastShape } from '../util/propShapes';
+import { toastShape } from '../propShapes';
+
+import '../stylesheets/toast.less';
 
 const propTypes = {
   toasts: PropTypes.arrayOf(toastShape),
diff --git a/superset/assets/src/messageToasts/constants.js 
b/superset/assets/src/messageToasts/constants.js
new file mode 100644
index 0000000..fd29e99
--- /dev/null
+++ b/superset/assets/src/messageToasts/constants.js
@@ -0,0 +1,5 @@
+// Toast types
+export const INFO_TOAST = 'INFO_TOAST';
+export const SUCCESS_TOAST = 'SUCCESS_TOAST';
+export const WARNING_TOAST = 'WARNING_TOAST';
+export const DANGER_TOAST = 'DANGER_TOAST';
diff --git a/superset/assets/src/dashboard/containers/ToastPresenter.jsx 
b/superset/assets/src/messageToasts/containers/ToastPresenter.jsx
similarity index 84%
rename from superset/assets/src/dashboard/containers/ToastPresenter.jsx
rename to superset/assets/src/messageToasts/containers/ToastPresenter.jsx
index 7e70abc..b66702f 100644
--- a/superset/assets/src/dashboard/containers/ToastPresenter.jsx
+++ b/superset/assets/src/messageToasts/containers/ToastPresenter.jsx
@@ -2,7 +2,7 @@ import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 import ToastPresenter from '../components/ToastPresenter';
 
-import { removeToast } from '../actions/messageToasts';
+import { removeToast } from '../actions';
 
 export default connect(
   ({ messageToasts: toasts }) => ({ toasts }),
diff --git a/superset/assets/src/messageToasts/enhancers/withToasts.jsx 
b/superset/assets/src/messageToasts/enhancers/withToasts.jsx
new file mode 100644
index 0000000..28a2d6b
--- /dev/null
+++ b/superset/assets/src/messageToasts/enhancers/withToasts.jsx
@@ -0,0 +1,26 @@
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+
+import {
+  addDangerToast,
+  addInfoToast,
+  addSuccessToast,
+  addWarningToast,
+} from '../actions';
+
+// To work properly the redux state must have a `messageToasts` subtree
+export default function withToasts(BaseComponent) {
+  return connect(
+    null,
+    dispatch =>
+      bindActionCreators(
+        {
+          addInfoToast,
+          addSuccessToast,
+          addWarningToast,
+          addDangerToast,
+        },
+        dispatch,
+      ),
+  )(BaseComponent);
+}
diff --git a/superset/assets/src/messageToasts/propShapes.js 
b/superset/assets/src/messageToasts/propShapes.js
new file mode 100644
index 0000000..a5e0f40
--- /dev/null
+++ b/superset/assets/src/messageToasts/propShapes.js
@@ -0,0 +1,21 @@
+import PropTypes from 'prop-types';
+
+import {
+  INFO_TOAST,
+  SUCCESS_TOAST,
+  WARNING_TOAST,
+  DANGER_TOAST,
+} from './constants';
+
+// eslint-disable-next-line import/prefer-default-export
+export const toastShape = PropTypes.shape({
+  id: PropTypes.string.isRequired,
+  toastType: PropTypes.oneOf([
+    INFO_TOAST,
+    SUCCESS_TOAST,
+    WARNING_TOAST,
+    DANGER_TOAST,
+  ]).isRequired,
+  text: PropTypes.string.isRequired,
+  duration: PropTypes.number,
+});
diff --git a/superset/assets/src/dashboard/reducers/messageToasts.js 
b/superset/assets/src/messageToasts/reducers/index.js
similarity index 84%
rename from superset/assets/src/dashboard/reducers/messageToasts.js
rename to superset/assets/src/messageToasts/reducers/index.js
index 7383ab0..ae1dfde 100644
--- a/superset/assets/src/dashboard/reducers/messageToasts.js
+++ b/superset/assets/src/messageToasts/reducers/index.js
@@ -1,4 +1,4 @@
-import { ADD_TOAST, REMOVE_TOAST } from '../actions/messageToasts';
+import { ADD_TOAST, REMOVE_TOAST } from '../actions';
 
 export default function messageToastsReducer(toasts = [], action) {
   switch (action.type) {
diff --git a/superset/assets/src/dashboard/stylesheets/toast.less 
b/superset/assets/src/messageToasts/stylesheets/toast.less
similarity index 88%
rename from superset/assets/src/dashboard/stylesheets/toast.less
rename to superset/assets/src/messageToasts/stylesheets/toast.less
index 1d1ebc5..fc62380 100644
--- a/superset/assets/src/dashboard/stylesheets/toast.less
+++ b/superset/assets/src/messageToasts/stylesheets/toast.less
@@ -1,3 +1,5 @@
+@import '../../dashboard/stylesheets/variables.less';
+
 .toast-presenter {
   position: fixed;
   bottom: 16px;
@@ -16,7 +18,7 @@
   box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.35);
   will-change: transform, opacity;
   transform: translateY(-100%);
-  transition: transform .3s, opacity .3s;
+  transition: transform 0.3s, opacity 0.3s;
 }
 
 .toast > button {
@@ -33,7 +35,7 @@
 }
 
 .toast:after {
-  content: "";
+  content: '';
   position: absolute;
   top: 0;
   left: 0;
diff --git 
a/superset/assets/src/messageToasts/utils/getToastsFromPyFlashMessages.js 
b/superset/assets/src/messageToasts/utils/getToastsFromPyFlashMessages.js
new file mode 100644
index 0000000..4c4d80c
--- /dev/null
+++ b/superset/assets/src/messageToasts/utils/getToastsFromPyFlashMessages.js
@@ -0,0 +1,22 @@
+import { addToast } from '../actions';
+import { INFO_TOAST, SUCCESS_TOAST, DANGER_TOAST } from '../constants';
+
+export default function toastsFromPyFlashMessages(flashMessages = []) {
+  const toasts = [];
+
+  flashMessages.forEach(([messageType, message]) => {
+    const toastType =
+      messageType === 'danger'
+        ? DANGER_TOAST
+        : (messageType === 'success' && SUCCESS_TOAST) || INFO_TOAST;
+
+    const toast = addToast({
+      text: message,
+      toastType,
+    }).payload;
+
+    toasts.push(toast);
+  });
+
+  return toasts;
+}
diff --git a/superset/assets/src/reduxUtils.js 
b/superset/assets/src/reduxUtils.js
index d843d27..17fcb65 100644
--- a/superset/assets/src/reduxUtils.js
+++ b/superset/assets/src/reduxUtils.js
@@ -67,9 +67,8 @@ export function addToArr(state, arrKey, obj) {
 export function initEnhancer(persist = true) {
   let enhancer = persist ? compose(persistState()) : compose();
   if (process.env.NODE_ENV === 'dev') {
-    /* eslint-disable no-underscore-dangle */
+    /* eslint-disable-next-line no-underscore-dangle */
     const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || 
compose;
-    /* eslint-enable */
     enhancer = persist ? composeEnhancers(persistState()) : composeEnhancers();
   }
   return enhancer;
diff --git a/superset/assets/src/utils/common.js 
b/superset/assets/src/utils/common.js
index c1a4eba..c5bdfb9 100644
--- a/superset/assets/src/utils/common.js
+++ b/superset/assets/src/utils/common.js
@@ -1,8 +1,7 @@
-/* global notify */
 /* eslint global-require: 0 */
 import $ from 'jquery';
 
-const d3 = window.d3 || require('d3');
+const d3 = require('d3');
 
 export const EARTH_CIRCUMFERENCE_KM = 40075.16;
 export const LUMINANCE_RED_WEIGHT = 0.2126;
@@ -72,7 +71,7 @@ export function getParamsFromUrl() {
   return newParams;
 }
 
-export function getShortUrl(longUrl, callback) {
+export function getShortUrl(longUrl, callback, onError) {
   $.ajax({
     type: 'POST',
     url: '/r/shortner/',
@@ -80,11 +79,11 @@ export function getShortUrl(longUrl, callback) {
     data: {
       data: '/' + longUrl,
     },
-    success: (data) => {
-      callback(data);
-    },
+    success: callback,
     error: () => {
-      notify.error('Error getting the short URL');
+      if (onError) {
+        onError('Error getting the short URL');
+      }
       callback(longUrl);
     },
   });
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index 37ee898..c3b9139 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -391,8 +391,8 @@ acorn@^5.0.0, acorn@^5.5.0:
   resolved 
"https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8";
 
 agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
-  version "4.2.0"
-  resolved 
"https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce";
+  version "4.2.1"
+  resolved 
"https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9";
   dependencies:
     es6-promisify "^5.0.0"
 
@@ -427,8 +427,8 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
     json-schema-traverse "^0.3.0"
 
 ajv@^6.1.0:
-  version "6.5.1"
-  resolved 
"https://registry.yarnpkg.com/ajv/-/ajv-6.5.1.tgz#88ebc1263c7133937d108b80c5572e64e1d9322d";
+  version "6.5.2"
+  resolved 
"https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360";
   dependencies:
     fast-deep-equal "^2.0.1"
     fast-json-stable-stringify "^2.0.0"
@@ -938,8 +938,8 @@ babel-istanbul@^0.12.2:
     wordwrap "1.0.x"
 
 babel-loader@^7.0.0:
-  version "7.1.4"
-  resolved 
"https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.4.tgz#e3463938bd4e6d55d1c174c5485d406a188ed015";
+  version "7.1.5"
+  resolved 
"https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68";
   dependencies:
     find-cache-dir "^1.0.0"
     loader-utils "^1.0.2"
@@ -1418,8 +1418,8 @@ base@^0.11.1:
     pascalcase "^0.1.1"
 
 bcrypt-pbkdf@^1.0.0:
-  version "1.0.1"
-  resolved 
"https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d";
+  version "1.0.2"
+  resolved 
"https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e";
   dependencies:
     tweetnacl "^0.14.3"
 
@@ -1507,8 +1507,8 @@ bops@0.0.6:
     to-utf8 "0.0.1"
 
 bowser@^1.2.0, bowser@^1.7.3:
-  version "1.9.3"
-  resolved 
"https://registry.yarnpkg.com/bowser/-/bowser-1.9.3.tgz#6643ae4d783f31683f6d23156976b74183862162";
+  version "1.9.4"
+  resolved 
"https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a";
 
 boxen@^1.2.1:
   version "1.3.0"
@@ -1556,10 +1556,6 @@ braces@^2.3.0, braces@^2.3.1:
     split-string "^3.0.2"
     to-regex "^3.0.1"
 
-brcast@^2.0.0:
-  version "2.0.2"
-  resolved 
"https://registry.yarnpkg.com/brcast/-/brcast-2.0.2.tgz#2db16de44140e418dc37fab10beec0369e78dcef";
-
 brfs@^1.3.0, brfs@^1.4.3, brfs@^1.4.4:
   version "1.6.1"
   resolved 
"https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3";
@@ -1778,12 +1774,12 @@ caniuse-api@^1.5.2:
     lodash.uniq "^4.5.0"
 
 caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
-  version "1.0.30000856"
-  resolved 
"https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000856.tgz#fbebb99abe15a5654fc7747ebb5315bdfde3358f";
+  version "1.0.30000864"
+  resolved 
"https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000864.tgz#35a4b2325a8d4553a46b516dbc233bf391d75555";
 
 caniuse-lite@^1.0.30000844:
-  version "1.0.30000856"
-  resolved 
"https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000856.tgz#ecc16978135a6f219b138991eb62009d25ee8daa";
+  version "1.0.30000864"
+  resolved 
"https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000864.tgz#7a08c78da670f23c06f11aa918831b8f2dd60ddc";
 
 capture-stack-trace@^1.0.0:
   version "1.0.0"
@@ -2181,8 +2177,8 @@ commander@2.9.0:
     graceful-readlink ">= 1.0.0"
 
 commander@^2.11.0, commander@^2.9.0:
-  version "2.15.1"
-  resolved 
"https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f";
+  version "2.16.0"
+  resolved 
"https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50";
 
 commander@~2.13.0:
   version "2.13.0"
@@ -2505,8 +2501,8 @@ csso@~2.3.1:
     source-map "^0.5.3"
 
 cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
-  version "0.3.2"
-  resolved 
"https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b";
+  version "0.3.4"
+  resolved 
"https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797";
 
 "cssstyle@>= 0.2.37 < 0.3.0":
   version "0.2.37"
@@ -2696,15 +2692,15 @@ datamaps@^0.5.8:
     topojson "^1.6.19"
 
 datatables.net-bs@^1.10.15:
-  version "1.10.18"
-  resolved 
"https://registry.yarnpkg.com/datatables.net-bs/-/datatables.net-bs-1.10.18.tgz#72c9ebe926f9189f891d4c474a629defc99753e6";
+  version "1.10.19"
+  resolved 
"https://registry.yarnpkg.com/datatables.net-bs/-/datatables.net-bs-1.10.19.tgz#08763b4e4d0cef1a427d019dc15e717c7ed67a4d";
   dependencies:
-    datatables.net "1.10.18"
+    datatables.net "1.10.19"
     jquery ">=1.7"
 
-datatables.net@1.10.18:
-  version "1.10.18"
-  resolved 
"https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.10.18.tgz#b6f045aa533101bcd33714e5338da8f905d3ef09";
+datatables.net@1.10.19:
+  version "1.10.19"
+  resolved 
"https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.10.19.tgz#97a1ed41c85e62d61040603481b59790a172dd1f";
   dependencies:
     jquery ">=1.7"
 
@@ -3023,8 +3019,8 @@ editor@~1.0.0:
   resolved 
"https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742";
 
 electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47:
-  version "1.3.50"
-  resolved 
"https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.50.tgz#7438b76f92b41b919f3fbdd350fbd0757dacddf7";
+  version "1.3.51"
+  resolved 
"https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.51.tgz#6a42b49daaf7f22a5b37b991daf949f34dbdb9b5";
 
 elliptic@^6.0.0:
   version "6.4.0"
@@ -3270,8 +3266,8 @@ eslint-module-utils@^2.2.0:
     pkg-dir "^1.0.0"
 
 eslint-plugin-import@^2.2.0:
-  version "2.12.0"
-  resolved 
"https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz#dad31781292d6664b25317fd049d2e2b2f02205d";
+  version "2.13.0"
+  resolved 
"https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz#df24f241175e312d91662dc91ca84064caec14ed";
   dependencies:
     contains-path "^0.1.0"
     debug "^2.6.8"
@@ -3297,20 +3293,20 @@ eslint-plugin-jsx-a11y@^5.1.1:
     jsx-ast-utils "^1.4.0"
 
 eslint-plugin-prettier@^2.6.0:
-  version "2.6.0"
-  resolved 
"https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7";
+  version "2.6.1"
+  resolved 
"https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.1.tgz#de902b4a66b7bca24296429a59a1cc04020ccbbd";
   dependencies:
     fast-diff "^1.1.1"
     jest-docblock "^21.0.0"
 
 eslint-plugin-react@^7.0.1:
-  version "7.9.1"
-  resolved 
"https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.9.1.tgz#101aadd15e7c7b431ed025303ac7b421a8e3dc15";
+  version "7.10.0"
+  resolved 
"https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.10.0.tgz#af5c1fef31c4704db02098f9be18202993828b50";
   dependencies:
     doctrine "^2.1.0"
-    has "^1.0.2"
+    has "^1.0.3"
     jsx-ast-utils "^2.0.1"
-    prop-types "^15.6.1"
+    prop-types "^15.6.2"
 
 eslint-restricted-globals@^0.1.1:
   version "0.1.1"
@@ -3580,10 +3576,6 @@ fast-levenshtein@~2.0.4:
   version "2.0.6"
   resolved 
"https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917";
 
-fast-memoize@^2.2.7:
-  version "2.4.0"
-  resolved 
"https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.4.0.tgz#2f79eca41c41112b0b70cf53ac3940e206574648";
-
 fastdom@^1.0.6:
   version "1.0.8"
   resolved 
"https://registry.yarnpkg.com/fastdom/-/fastdom-1.0.8.tgz#10f9d36998fd6efae30e529597d788e750c9febb";
@@ -3600,7 +3592,7 @@ fault@^1.0.2:
   dependencies:
     format "^0.2.2"
 
-fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.4, fbjs@^0.8.9:
+fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.9:
   version "0.8.17"
   resolved 
"https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd";
   dependencies:
@@ -4087,26 +4079,6 @@ gl-vec4@^1.0.0, gl-vec4@^1.0.1:
   version "1.0.1"
   resolved 
"https://registry.yarnpkg.com/gl-vec4/-/gl-vec4-1.0.1.tgz#97d96878281b14b532cbce101785dfd1cb340964";
 
-glamor@^2.20.24:
-  version "2.20.40"
-  resolved 
"https://registry.yarnpkg.com/glamor/-/glamor-2.20.40.tgz#f606660357b7cf18dface731ad1a2cfa93817f05";
-  dependencies:
-    fbjs "^0.8.12"
-    inline-style-prefixer "^3.0.6"
-    object-assign "^4.1.1"
-    prop-types "^15.5.10"
-    through "^2.3.8"
-
-glamorous@^3.13.1:
-  version "3.25.0"
-  resolved 
"https://registry.yarnpkg.com/glamorous/-/glamorous-3.25.0.tgz#d6d66c3dfffdc194761469adcbd996d4b70222e1";
-  dependencies:
-    brcast "^2.0.0"
-    fast-memoize "^2.2.7"
-    html-tag-names "^1.1.1"
-    react-html-attributes "^1.3.0"
-    svg-tag-names "^1.1.0"
-
 glob-base@^0.3.0:
   version "0.3.0"
   resolved 
"https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4";
@@ -4344,7 +4316,7 @@ has-values@^1.0.0:
     is-number "^3.0.0"
     kind-of "^4.0.0"
 
-has@^1.0.1, has@^1.0.2:
+has@^1.0.1, has@^1.0.3:
   version "1.0.3"
   resolved 
"https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796";
   dependencies:
@@ -4440,8 +4412,8 @@ home-or-tmp@^2.0.0:
     os-tmpdir "^1.0.1"
 
 hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, 
hosted-git-info@^2.6.0:
-  version "2.6.0"
-  resolved 
"https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222";
+  version "2.6.1"
+  resolved 
"https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.1.tgz#6e4cee78b01bb849dcf93527708c69fdbee410df";
 
 hosted-git-info@~2.1.5:
   version "2.1.5"
@@ -4451,20 +4423,12 @@ html-comment-regex@^1.1.0:
   version "1.1.1"
   resolved 
"https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e";
 
-html-element-attributes@^1.0.0:
-  version "1.3.1"
-  resolved 
"https://registry.yarnpkg.com/html-element-attributes/-/html-element-attributes-1.3.1.tgz#9fa6a2e37e6b61790a303e87ddbbb9746e8c035f";
-
 html-encoding-sniffer@^1.0.1:
   version "1.0.2"
   resolved 
"https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8";
   dependencies:
     whatwg-encoding "^1.0.1"
 
-html-tag-names@^1.1.1:
-  version "1.1.3"
-  resolved 
"https://registry.yarnpkg.com/html-tag-names/-/html-tag-names-1.1.3.tgz#f81f75e59d626cb8a958a19e58f90c1d69707b82";
-
 htmlparser2@^3.9.1:
   version "3.9.2"
   resolved 
"https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338";
@@ -4767,8 +4731,8 @@ is-builtin-module@^1.0.0:
     builtin-modules "^1.0.0"
 
 is-callable@^1.1.1, is-callable@^1.1.3:
-  version "1.1.3"
-  resolved 
"https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2";
+  version "1.1.4"
+  resolved 
"https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75";
 
 is-ci@^1.0.10:
   version "1.1.0"
@@ -4933,12 +4897,6 @@ is-object@~0.1.2:
   version "0.1.2"
   resolved 
"https://registry.yarnpkg.com/is-object/-/is-object-0.1.2.tgz#00efbc08816c33cfc4ac8251d132e10dc65098d7";
 
-is-odd@^2.0.0:
-  version "2.0.0"
-  resolved 
"https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24";
-  dependencies:
-    is-number "^4.0.0"
-
 is-path-cwd@^1.0.0:
   version "1.0.0"
   resolved 
"https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d";
@@ -5812,7 +5770,7 @@ math-random@^1.0.1:
   version "1.0.1"
   resolved 
"https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac";
 
-math.gl@^1.1.0, math.gl@^1.1.3, math.gl@^1.2.1:
+math.gl@^1.1.0, math.gl@^1.2.1:
   version "1.2.1"
   resolved 
"https://registry.yarnpkg.com/math.gl/-/math.gl-1.2.1.tgz#3c7da0ae4f3383116c24bc183533cc4d7b8065a9";
   dependencies:
@@ -5823,6 +5781,17 @@ math.gl@^1.1.0, math.gl@^1.1.3, math.gl@^1.2.1:
     gl-vec3 "^1.0.3"
     gl-vec4 "^1.0.1"
 
+math.gl@^2.0.0:
+  version "2.0.0"
+  resolved 
"https://registry.yarnpkg.com/math.gl/-/math.gl-2.0.0.tgz#c41cf8f5cfce820161511c435d3f706eebd7deb0";
+  dependencies:
+    gl-mat3 "^1.0.0"
+    gl-mat4 "^1.1.4"
+    gl-quat "^1.0.0"
+    gl-vec2 "^1.0.0"
+    gl-vec3 "^1.0.3"
+    gl-vec4 "^1.0.1"
+
 mathfn@^1.0.0:
   version "1.0.1"
   resolved 
"https://registry.yarnpkg.com/mathfn/-/mathfn-1.0.1.tgz#650a0b183b0102debe94e42a807dc6b4d2cc57bd";
@@ -6105,20 +6074,15 @@ nan@^2.9.2:
   version "2.10.0"
   resolved 
"https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f";
 
-nanoid@^0.2.2:
-  version "0.2.2"
-  resolved 
"https://registry.yarnpkg.com/nanoid/-/nanoid-0.2.2.tgz#e2ebc6ad3db5e0454fd8124d30ca39b06555fe56";
-
 nanomatch@^1.2.9:
-  version "1.2.9"
-  resolved 
"https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2";
+  version "1.2.13"
+  resolved 
"https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119";
   dependencies:
     arr-diff "^4.0.0"
     array-unique "^0.3.2"
     define-property "^2.0.2"
     extend-shallow "^3.0.2"
     fragment-cache "^0.2.1"
-    is-odd "^2.0.0"
     is-windows "^1.0.2"
     kind-of "^6.0.2"
     object.pick "^1.3.0"
@@ -6243,8 +6207,8 @@ node-libs-browser@^2.0.0:
     vm-browserify "0.0.4"
 
 node-pre-gyp@^0.10.0:
-  version "0.10.0"
-  resolved 
"https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz#6e4ef5bb5c5203c6552448828c852c40111aac46";
+  version "0.10.2"
+  resolved 
"https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.2.tgz#e8945c20ef6795a20aac2b44f036eb13cf5146e3";
   dependencies:
     detect-libc "^1.0.2"
     mkdirp "^0.5.1"
@@ -6252,7 +6216,7 @@ node-pre-gyp@^0.10.0:
     nopt "^4.0.1"
     npm-packlist "^1.1.6"
     npmlog "^4.0.2"
-    rc "^1.1.7"
+    rc "^1.2.7"
     rimraf "^2.6.1"
     semver "^5.3.0"
     tar "^4"
@@ -7444,8 +7408,8 @@ preserve@^0.2.0:
   resolved 
"https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b";
 
 prettier@^1.12.1:
-  version "1.13.5"
-  resolved 
"https://registry.yarnpkg.com/prettier/-/prettier-1.13.5.tgz#7ae2076998c8edce79d63834e9b7b09fead6bfd0";
+  version "1.13.7"
+  resolved 
"https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281";
 
 prismjs@^1.8.4:
   version "1.15.0"
@@ -7522,7 +7486,7 @@ prop-types@15.5.10:
     fbjs "^0.8.9"
     loose-envify "^1.3.1"
 
-prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, 
prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1:
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, 
prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, 
prop-types@^15.6.2:
   version "15.6.2"
   resolved 
"https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102";
   dependencies:
@@ -7704,7 +7668,7 @@ rc-config-loader@^2.0.1:
     path-exists "^2.1.0"
     require-from-string "^2.0.1"
 
-rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
+rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
   version "1.2.8"
   resolved 
"https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed";
   dependencies:
@@ -7714,8 +7678,8 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
     strip-json-comments "~2.0.1"
 
 re-resizable@^4.3.1:
-  version "4.5.1"
-  resolved 
"https://registry.yarnpkg.com/re-resizable/-/re-resizable-4.5.1.tgz#4688e8311ea4b70d558f7aebb3168a25926e62d9";
+  version "4.7.1"
+  resolved 
"https://registry.yarnpkg.com/re-resizable/-/re-resizable-4.7.1.tgz#3eca5bb94a6059d14311786cfd2d430bc9f7fba0";
 
 react-ace@^5.10.0:
   version "5.10.0"
@@ -7743,15 +7707,6 @@ react-addons-test-utils@^15.6.2:
   version "15.6.2"
   resolved 
"https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz#c12b6efdc2247c10da7b8770d185080a7b047156";
 
-react-alert@^2.3.0:
-  version "2.4.0"
-  resolved 
"https://registry.yarnpkg.com/react-alert/-/react-alert-2.4.0.tgz#b4c9ce74919b46be330a7addbf46e7561c295bc7";
-  dependencies:
-    glamor "^2.20.24"
-    glamorous "^3.13.1"
-    nanoid "^0.2.2"
-    react-transition-group "^1.1.2"
-
 react-bootstrap-slider@2.1.5:
   version "2.1.5"
   resolved 
"https://registry.yarnpkg.com/react-bootstrap-slider/-/react-bootstrap-slider-2.1.5.tgz#2f79e57b69ddf2b5bd23310bddbd2de0c6bdfef3";
@@ -7853,12 +7808,6 @@ react-grid-layout@0.16.6:
     react-draggable "3.x"
     react-resizable "1.x"
 
-react-html-attributes@^1.3.0:
-  version "1.4.2"
-  resolved 
"https://registry.yarnpkg.com/react-html-attributes/-/react-html-attributes-1.4.2.tgz#0d2ccf134fc79b2d3543837dc1591d32b7b903f9";
-  dependencies:
-    html-element-attributes "^1.0.0"
-
 react-input-autosize@^2.1.2:
   version "2.2.1"
   resolved 
"https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8";
@@ -7874,14 +7823,14 @@ react-lifecycles-compat@^3.0.0, 
react-lifecycles-compat@^3.0.4:
   resolved 
"https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362";
 
 react-map-gl@^3.0.4:
-  version "3.2.10"
-  resolved 
"https://registry.yarnpkg.com/react-map-gl/-/react-map-gl-3.2.10.tgz#30ce9a26be4aea659c4fef981962ceb6feebe28a";
+  version "3.3.0"
+  resolved 
"https://registry.yarnpkg.com/react-map-gl/-/react-map-gl-3.3.0.tgz#dad906ec4c56a51873884325c44025d49516a9ea";
   dependencies:
     babel-runtime "^6.23.0"
     bowser "^1.2.0"
     immutable "^3.8.2"
     mapbox-gl "0.45"
-    math.gl "^1.1.3"
+    math.gl "^1.1.0"
     mjolnir.js "^1.2.1"
     prop-types "^15.5.7"
     viewport-mercator-project "^5.1.0"
@@ -7897,8 +7846,8 @@ react-markdown@^3.3.0:
     xtend "^4.0.1"
 
 react-modal@^3.1.7:
-  version "3.4.5"
-  resolved 
"https://registry.yarnpkg.com/react-modal/-/react-modal-3.4.5.tgz#75a7eefb8f4c8247278d5ce1c41249d7785d9f69";
+  version "3.5.1"
+  resolved 
"https://registry.yarnpkg.com/react-modal/-/react-modal-3.5.1.tgz#33d38527def90ea324848f7d63e53acc4468a451";
   dependencies:
     exenv "^1.2.0"
     prop-types "^15.5.10"
@@ -7973,16 +7922,17 @@ react-sortable-hoc@^0.8.3:
     prop-types "^15.5.7"
 
 react-split-pane@^0.1.63, react-split-pane@^0.1.66:
-  version "0.1.77"
-  resolved 
"https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.77.tgz#f0c8cd18d076bbac900248dcf6dbcec02d5340db";
+  version "0.1.81"
+  resolved 
"https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.81.tgz#b1e8b82e0a6edd10f18fd639a5f512db3cbbb4e6";
   dependencies:
     inline-style-prefixer "^3.0.6"
     prop-types "^15.5.10"
+    react-lifecycles-compat "^3.0.4"
     react-style-proptype "^3.0.0"
 
 react-sticky@^6.0.2:
-  version "6.0.2"
-  resolved 
"https://registry.yarnpkg.com/react-sticky/-/react-sticky-6.0.2.tgz#d301c1b5307649220dbc045fcbacd077885c5ede";
+  version "6.0.3"
+  resolved 
"https://registry.yarnpkg.com/react-sticky/-/react-sticky-6.0.3.tgz#7a18b643e1863da113d7f7036118d2a75d9ecde4";
   dependencies:
     prop-types "^15.5.8"
     raf "^3.3.0"
@@ -8010,7 +7960,7 @@ react-test-renderer@^15.6.2:
     fbjs "^0.8.9"
     object-assign "^4.1.0"
 
-react-transition-group@^1.1.2, react-transition-group@^1.2.0:
+react-transition-group@^1.2.0:
   version "1.2.1"
   resolved 
"https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.1.tgz#e11f72b257f921b213229a774df46612346c7ca6";
   dependencies:
@@ -8901,8 +8851,8 @@ socks@^1.1.10:
     smart-buffer "^1.0.13"
 
 socks@~2.2.0:
-  version "2.2.0"
-  resolved 
"https://registry.yarnpkg.com/socks/-/socks-2.2.0.tgz#144985b3331ced3ab5ccbee640ab7cb7d43fdd1f";
+  version "2.2.1"
+  resolved 
"https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9";
   dependencies:
     ip "^1.1.5"
     smart-buffer "^4.0.1"
@@ -9269,10 +9219,6 @@ supports-color@^5.1.0, supports-color@^5.3.0, 
supports-color@^5.4.0:
   dependencies:
     has-flag "^3.0.0"
 
-svg-tag-names@^1.1.0:
-  version "1.1.1"
-  resolved 
"https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a";
-
 svgo@^0.7.0:
   version "0.7.2"
   resolved 
"https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5";
@@ -9360,7 +9306,7 @@ through2@~0.6.3:
     readable-stream ">=1.0.33-1 <1.1.0-0"
     xtend ">=4.0.0 <4.1.0-0"
 
-through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, 
through@~2.3.4:
+through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4:
   version "2.3.8"
   resolved 
"https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5";
 
@@ -9442,8 +9388,8 @@ topojson@^1.6.19:
     shapefile "0.3"
 
 tough-cookie@^2.3.2:
-  version "2.4.2"
-  resolved 
"https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.2.tgz#aa9133154518b494efab98a58247bfc38818c00c";
+  version "2.4.3"
+  resolved 
"https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781";
   dependencies:
     psl "^1.1.24"
     punycode "^1.4.1"
@@ -9557,8 +9503,8 @@ uglifyjs-webpack-plugin@^0.4.6:
     webpack-sources "^1.0.1"
 
 uglifyjs-webpack-plugin@^1.1.0:
-  version "1.2.6"
-  resolved 
"https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.6.tgz#f4bb44f02431e82b301d8d4624330a6a35729381";
+  version "1.2.7"
+  resolved 
"https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz#57638dd99c853a1ebfe9d97b42160a8a507f9d00";
   dependencies:
     cacache "^10.0.4"
     find-cache-dir "^1.0.0"
@@ -9768,8 +9714,8 @@ util@^0.10.3:
     inherits "2.0.3"
 
 uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1:
-  version "3.2.1"
-  resolved 
"https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14";
+  version "3.3.2"
+  resolved 
"https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131";
 
 v8flags@^2.1.1:
   version "2.1.1"
@@ -9828,10 +9774,10 @@ vfile@^2.0.0:
     vfile-message "^1.0.0"
 
 viewport-mercator-project@^5.0.0, viewport-mercator-project@^5.1.0:
-  version "5.1.0"
-  resolved 
"https://registry.yarnpkg.com/viewport-mercator-project/-/viewport-mercator-project-5.1.0.tgz#68bc5586988c2808d1456e1eff950d424eccec16";
+  version "5.2.0"
+  resolved 
"https://registry.yarnpkg.com/viewport-mercator-project/-/viewport-mercator-project-5.2.0.tgz#2c50bc624a085d01a3a486f22ec329c0511fe4bd";
   dependencies:
-    math.gl "^1.1.0"
+    math.gl "^2.0.0"
 
 vlq@^0.2.2:
   version "0.2.3"
@@ -10089,8 +10035,8 @@ yargs-parser@^9.0.2:
     camelcase "^4.1.0"
 
 yargs@^11.0.0:
-  version "11.0.0"
-  resolved 
"https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b";
+  version "11.1.0"
+  resolved 
"https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77";
   dependencies:
     cliui "^4.0.0"
     decamelize "^1.1.1"

Reply via email to