From fc3b68e23433522b3a6d7327cc95199bf01dcf96 Mon Sep 17 00:00:00 2001 From: timifasubaa <30888507+timifasubaa@users.noreply.github.com> Date: Mon, 22 Oct 2018 18:36:07 -0700 Subject: [PATCH] [Sqllab] Add offline state to sqllab (#6013) * add timeout and refresh for failed backend * show offline state instead of refreshing * add southpane tests --- .../javascripts/sqllab/SouthPane_spec.jsx | 37 +++++++++++++++++++ .../sqllab/SqlEditorLeftBar_spec.jsx | 11 +++++- .../sqllab/TabbedSqlEditors_spec.jsx | 6 +++ superset/assets/src/SqlLab/actions.js | 5 +++ .../SqlLab/components/QueryAutoRefresh.jsx | 7 +++- .../src/SqlLab/components/QuerySearch.jsx | 2 +- .../src/SqlLab/components/SouthPane.jsx | 12 +++++- .../SqlLab/components/SqlEditorLeftBar.jsx | 17 +++++++-- .../SqlLab/components/TabbedSqlEditors.jsx | 4 ++ superset/assets/src/SqlLab/constants.js | 14 ++++--- superset/assets/src/SqlLab/getInitialState.js | 5 ++- superset/assets/src/SqlLab/reducers.js | 3 ++ 12 files changed, 106 insertions(+), 17 deletions(-) create mode 100644 superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx 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 {