williaster closed pull request #5355: get rid of global `notify`
URL: https://github.com/apache/incubator-superset/pull/5355
 
 
   

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

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

diff --git a/superset/assets/package.json b/superset/assets/package.json
index 6a3935422a..9bcec4d0b9 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 98e6e2cf68..1aa0074ccf 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 4b2848085c..e58bb11a48 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 655f0bf7b8..514442fc00 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 c8d1390850..68dc783c4c 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 18129666cd..418e9c5812 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 0000000000..a3f86e3a17
--- /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 0000000000..a20502b7f0
--- /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 7545ad6b09..aa04adcb3c 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 6ed0bc5adf..ce3396cd62 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 07726a8c73..087374c91b 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 5280312bb6..8d7127087e 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 0000000000..a3c7ce9068
--- /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 9adec4fbbb..0000000000
--- 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 8d9facb0c2..ce76e309f4 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 dcbb64e1a1..662cb352f3 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 df7035a96d..16f1f8bf36 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 d1b58d32ed..b0689650da 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 c898662f57..0846af8166 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 b80a962606..5eb4802a7d 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 34c32a23a0..5909ca8241 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 c05a745884..510b5d5bda 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 a23ceb5d57..2931d13b46 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 540bfe7b03..58db1a75c3 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 3698a2a258..8a0c084373 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 55e06cc146..4bd034e712 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 e6a19d911f..d13d99376b 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 7102880e99..73ba069761 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 37626a83bc..a4cb4eb055 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 08c0e9cdc6..a255ca631b 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 b9acc160d5..0c5b272996 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 14ba0c0e0b..c02656e088 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 0000000000..9452ac570c
--- /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 4e2eae898c..24983de9bc 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 690126d2f0..a55a022721 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 1718fc78f5..fa6d9e6364 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 672c56d59d..0000000000
--- 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 aa9ae96ef5..1efd4f7122 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 bd01146143..149ead7fc9 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 5c92ff26f0..17f6d46da0 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 5f5479e81c..80d4bdf1e1 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 9621a4972a..ecb528dc89 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 dec97b7cb6..3740404da1 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 7381486f24..a8701207cb 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 6ba4159388..f1b88e4646 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';
@@ -368,7 +368,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 aa622ab078..7a44156857 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 d7e898e901..47d1e2416f 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 00bf2bfec1..b519e2eed7 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 787cd5f0bf..a5be96fdf4 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 b69c7b0530..08a095673e 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 bfe24cc378..09d72448d0 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 f15519094b..3c06e14cf3 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 c275b9c4d5..d64d3fe81d 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 d63d6fe806..545ad1055a 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 ec5a365322..ef8c4172b7 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 07870e4312..283b5f5297 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 953b0b5fca..461eb0f86b 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 0000000000..a3f86e3a17
--- /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 0000000000..a20502b7f0
--- /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 e5c04e6ca4..2ad888ba3e 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 a2b5f0a68c..70cda51aa4 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 19d44b0e8a..95c01b8442 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 0000000000..fd29e996c6
--- /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 7e70abc594..b66702fb8c 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 0000000000..28a2d6b08f
--- /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 0000000000..a5e0f40258
--- /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 7383ab0386..ae1dfdef31 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 1d1ebc53d4..fc623800ad 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 0000000000..4c4d80cee3
--- /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 d843d279a2..17fcb65897 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 c1a4eba94b..c5bdfb9f6d 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 37ee898cd1..c3b91390bb 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"


 

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


With regards,
Apache Git Services

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

Reply via email to