diff --git a/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx b/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx new file mode 100644 index 000000000..9836583b7 --- /dev/null +++ b/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; + +import { shallow } from 'enzyme'; + +import { STATUS_OPTIONS } from '../../../src/SqlLab/constants'; +import { initialState } from './fixtures'; +import SouthPane from '../../../src/SqlLab/components/SouthPane'; + +describe('SouthPane', () => { + const middlewares = [thunk]; + const mockStore = configureStore(middlewares); + const store = mockStore(initialState); + + const mockedProps = { + editorQueries: [], + dataPreviewQueries: [], + actions: {}, + activeSouthPaneTab: '', + height: 1, + databases: {}, + offline: false, + }; + + const getWrapper = () => ( + shallow(, { + context: { store }, + }).dive()); + + let wrapper; + it('should render offline when the state is offline', () => { + wrapper = getWrapper(); + wrapper.setProps({ offline: true }); + expect(wrapper.find('.m-r-3').render().text()).toBe(STATUS_OPTIONS.offline); + }); +}); diff --git a/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx b/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx index b233e19d4..9d3c3f64a 100644 --- a/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx +++ b/superset/assets/spec/javascripts/sqllab/SqlEditorLeftBar_spec.jsx @@ -1,9 +1,11 @@ import React from 'react'; +import configureStore from 'redux-mock-store'; import { shallow } from 'enzyme'; import sinon from 'sinon'; import fetchMock from 'fetch-mock'; +import thunk from 'redux-thunk'; -import { table, defaultQueryEditor, databases, tables } from './fixtures'; +import { table, defaultQueryEditor, databases, initialState, tables } from './fixtures'; import SqlEditorLeftBar from '../../../src/SqlLab/components/SqlEditorLeftBar'; import TableElement from '../../../src/SqlLab/components/TableElement'; @@ -21,11 +23,16 @@ describe('SqlEditorLeftBar', () => { database: {}, height: 0, }; + const middlewares = [thunk]; + const mockStore = configureStore(middlewares); + const store = mockStore(initialState); let wrapper; beforeEach(() => { - wrapper = shallow(); + wrapper = shallow(, { + context: { store }, + }).dive(); }); it('is valid', () => { diff --git a/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx b/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx index 046e2a6ab..33d1e476a 100644 --- a/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx +++ b/superset/assets/spec/javascripts/sqllab/TabbedSqlEditors_spec.jsx @@ -166,4 +166,10 @@ describe('TabbedSqlEditors', () => { const lastTab = wrapper.find(Tab).last(); expect(lastTab.props().eventKey).toContain('add_tab'); }); + it('should disable new tab when offline', () => { + wrapper = getWrapper(); + expect(wrapper.find(Tab).last().props().disabled).toBe(false); + wrapper.setProps({ offline: true }); + expect(wrapper.find(Tab).last().props().disabled).toBe(true); + }); }); diff --git a/superset/assets/src/SqlLab/actions.js b/superset/assets/src/SqlLab/actions.js index 8c9ef2d49..91e848649 100644 --- a/superset/assets/src/SqlLab/actions.js +++ b/superset/assets/src/SqlLab/actions.js @@ -34,6 +34,7 @@ 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 REFRESH_QUERIES = 'REFRESH_QUERIES'; +export const SET_USER_OFFLINE = 'SET_USER_OFFLINE'; export const RUN_QUERY = 'RUN_QUERY'; export const START_QUERY = 'START_QUERY'; export const STOP_QUERY = 'STOP_QUERY'; @@ -342,6 +343,10 @@ export function refreshQueries(alteredQueries) { return { type: REFRESH_QUERIES, alteredQueries }; } +export function setUserOffline(offline) { + return { type: SET_USER_OFFLINE, offline }; +} + export function persistEditorHeight(queryEditor, currentHeight) { return { type: QUERY_EDITOR_PERSIST_HEIGHT, queryEditor, currentHeight }; } diff --git a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx index 0b0936458..ea6e78091 100644 --- a/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx +++ b/superset/assets/src/SqlLab/components/QueryAutoRefresh.jsx @@ -9,6 +9,7 @@ import * as Actions from '../actions'; const QUERY_UPDATE_FREQ = 2000; const QUERY_UPDATE_BUFFER_MS = 5000; const MAX_QUERY_AGE_TO_POLL = 21600000; +const QUERY_TIMEOUT_LIMIT = 7000; class QueryAutoRefresh extends React.PureComponent { componentWillMount() { @@ -44,11 +45,15 @@ class QueryAutoRefresh extends React.PureComponent { if (this.shouldCheckForQueries()) { SupersetClient.get({ endpoint: `/superset/queries/${this.props.queriesLastUpdate - QUERY_UPDATE_BUFFER_MS}`, + timeout: QUERY_TIMEOUT_LIMIT, }).then(({ json }) => { if (Object.keys(json).length > 0) { this.props.actions.refreshQueries(json); } - }); + this.props.actions.setUserOffline(false); + }).catch(() => { + this.props.actions.setUserOffline(true); + }); } } render() { diff --git a/superset/assets/src/SqlLab/components/QuerySearch.jsx b/superset/assets/src/SqlLab/components/QuerySearch.jsx index a3d9ddf3a..9e920295a 100644 --- a/superset/assets/src/SqlLab/components/QuerySearch.jsx +++ b/superset/assets/src/SqlLab/components/QuerySearch.jsx @@ -227,7 +227,7 @@ class QuerySearch extends React.PureComponent {