diff --git a/superset/assets/javascripts/SqlLab/actions.js b/superset/assets/javascripts/SqlLab/actions.js
index 0effacefcf1..6d62436fcbe 100644
--- a/superset/assets/javascripts/SqlLab/actions.js
+++ b/superset/assets/javascripts/SqlLab/actions.js
@@ -247,6 +247,17 @@ export function mergeTable(table, query) {
export function addTable(query, tableName, schemaName) {
return function (dispatch) {
+ let table = {
+ dbId: query.dbId,
+ queryEditorId: query.id,
+ schema: schemaName,
+ name: tableName,
+ isMetadataLoading: true,
+ isExtraMetadataLoading: true,
+ expanded: false,
+ };
+ dispatch(mergeTable(table));
+
let url = `/superset/table/${query.dbId}/${tableName}/${schemaName}/`;
$.get(url, (data) => {
const dataPreviewQuery = {
@@ -260,35 +271,21 @@ export function addTable(query, tableName, schemaName) {
ctas: false,
};
// Merge table to tables in state
- dispatch(mergeTable(
- Object.assign(data, {
- dbId: query.dbId,
- queryEditorId: query.id,
- schema: schemaName,
- expanded: true,
- }), dataPreviewQuery),
- );
+ table = Object.assign({}, table, data, {
+ expanded: true,
+ isMetadataLoading: false,
+ });
+ dispatch(mergeTable(table, dataPreviewQuery));
// Run query to get preview data for table
dispatch(runQuery(dataPreviewQuery));
})
.fail(() => {
- dispatch(
- addAlert({
- msg: 'Error occurred while fetching metadata',
- bsStyle: 'danger',
- }),
- );
+ notify.error('Error occurred while fetching table metadata');
});
url = `/superset/extra_table_metadata/${query.dbId}/${tableName}/${schemaName}/`;
$.get(url, (data) => {
- const table = {
- dbId: query.dbId,
- queryEditorId: query.id,
- schema: schemaName,
- name: tableName,
- };
- Object.assign(table, data);
+ table = Object.assign({}, table, data, { isExtraMetadataLoading: false });
dispatch(mergeTable(table));
});
};
diff --git a/superset/assets/javascripts/SqlLab/components/SqlEditorLeftBar.jsx b/superset/assets/javascripts/SqlLab/components/SqlEditorLeftBar.jsx
index ff6da18651c..e70ed98dcbe 100644
--- a/superset/assets/javascripts/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset/assets/javascripts/SqlLab/components/SqlEditorLeftBar.jsx
@@ -1,3 +1,4 @@
+/* global notify */
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'react-bootstrap';
@@ -82,6 +83,10 @@ class SqlEditorLeftBar extends React.PureComponent {
tableOptions: data.options,
tableLength: data.tableLength,
});
+ })
+ .fail(() => {
+ this.setState({ tableLoading: false, tableOptions: [], tableLength: 0 });
+ notify.error('Error while fetching table list');
});
} else {
this.setState({ tableLoading: false, tableOptions: [], filterOptions: null });
@@ -104,11 +109,7 @@ class SqlEditorLeftBar extends React.PureComponent {
this.props.actions.queryEditorSetSchema(this.props.queryEditor, schemaName);
this.fetchTables(this.props.queryEditor.dbId, schemaName);
}
- this.setState({ tableLoading: true });
- // TODO: handle setting the tableLoading state depending on success or
- // failure of the addTable async call in the action.
this.props.actions.addTable(this.props.queryEditor, tableName, schemaName);
- this.setState({ tableLoading: false });
}
changeSchema(schemaOpt) {
const schema = (schemaOpt) ? schemaOpt.value : null;
@@ -122,8 +123,11 @@ class SqlEditorLeftBar extends React.PureComponent {
const url = `/superset/schemas/${actualDbId}/`;
$.get(url, (data) => {
const schemaOptions = data.schemas.map(s => ({ value: s, label: s }));
- this.setState({ schemaOptions });
- this.setState({ schemaLoading: false });
+ this.setState({ schemaOptions, schemaLoading: false });
+ })
+ .fail(() => {
+ this.setState({ schemaLoading: false, schemaOptions: [] });
+ notify.error('Error while fetching schema list');
});
}
}
@@ -145,6 +149,7 @@ class SqlEditorLeftBar extends React.PureComponent {
'_od_DatabaseView=asc'
}
onChange={this.onDatabaseChange.bind(this)}
+ onAsyncError={() => notify.error('Error while fetching database list')}
value={this.props.queryEditor.dbId}
databaseId={this.props.queryEditor.dbId}
actions={this.props.actions}
diff --git a/superset/assets/javascripts/SqlLab/components/TableElement.jsx b/superset/assets/javascripts/SqlLab/components/TableElement.jsx
index dbcb0291a66..fc8ae0c6699 100644
--- a/superset/assets/javascripts/SqlLab/components/TableElement.jsx
+++ b/superset/assets/javascripts/SqlLab/components/TableElement.jsx
@@ -8,6 +8,7 @@ import CopyToClipboard from '../../components/CopyToClipboard';
import Link from './Link';
import ColumnElement from './ColumnElement';
import ModalTrigger from '../../components/ModalTrigger';
+import Loading from '../../components/Loading';
const propTypes = {
table: PropTypes.object,
@@ -62,7 +63,7 @@ class TableElement extends React.PureComponent {
this.props.actions.removeTable(this.props.table);
}
- renderHeader() {
+ renderWell() {
const table = this.props.table;
let header;
if (table.partitions) {
@@ -97,37 +98,9 @@ class TableElement extends React.PureComponent {
}
return header;
}
- renderMetadata() {
- const table = this.props.table;
- let cols;
- if (table.columns) {
- cols = table.columns.slice();
- if (this.state.sortColumns) {
- cols.sort((a, b) => a.name.toUpperCase() > b.name.toUpperCase());
- }
- }
- const metadata = (
-
-
+ );
+}
+Loading.propTypes = propTypes;
+Loading.defaultProps = defaultProps;
diff --git a/superset/assets/spec/helpers/browser.js b/superset/assets/spec/helpers/browser.js
index 18072fe6851..a74ce3ef5cc 100644
--- a/superset/assets/spec/helpers/browser.js
+++ b/superset/assets/spec/helpers/browser.js
@@ -1,12 +1,14 @@
/* eslint no-undef: 0, no-native-reassign: 0 */
+import 'babel-polyfill';
+import chai from 'chai';
+import jsdom from 'jsdom';
require('babel-register')();
-const jsdom = require('jsdom').jsdom;
-
const exposedProperties = ['window', 'navigator', 'document'];
-global.document = jsdom('');
+global.jsdom = jsdom.jsdom;
+global.document = global.jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
@@ -20,3 +22,19 @@ global.navigator = {
platform: 'linux',
appName: 'Netscape',
};
+
+// Configuration copied from https://github.com/sinonjs/sinon/issues/657
+// allowing for sinon.fakeServer to work
+
+global.window = global.document.defaultView;
+global.XMLHttpRequest = global.window.XMLHttpRequest;
+
+global.sinon = require('sinon');
+
+global.expect = chai.expect;
+global.assert = chai.assert;
+
+global.sinon.useFakeXMLHttpRequest();
+
+global.window.XMLHttpRequest = global.XMLHttpRequest;
+global.$ = require('jquery')(global.window);
diff --git a/superset/assets/spec/javascripts/components/AsyncSelect_spec.jsx b/superset/assets/spec/javascripts/components/AsyncSelect_spec.jsx
index 79c63739b65..5b498464b0c 100644
--- a/superset/assets/spec/javascripts/components/AsyncSelect_spec.jsx
+++ b/superset/assets/spec/javascripts/components/AsyncSelect_spec.jsx
@@ -1,10 +1,9 @@
import React from 'react';
import Select from 'react-select';
-import { shallow } from 'enzyme';
+import { mount, shallow } from 'enzyme';
import { describe, it } from 'mocha';
import { expect } from 'chai';
import sinon from 'sinon';
-import $ from 'jquery';
import AsyncSelect from '../../../javascripts/components/AsyncSelect';
@@ -39,30 +38,32 @@ describe('AsyncSelect', () => {
});
describe('auto select', () => {
- let stub;
+ let server;
beforeEach(() => {
- stub = sinon.stub($, 'get');
- stub.yields();
+ server = sinon.fakeServer.create();
+ server.respondWith([
+ 200, { 'Content-Type': 'application/json' }, JSON.stringify({}),
+ ]);
});
afterEach(() => {
- stub.restore();
+ server.restore();
});
it('should be off by default', () => {
- const wrapper = shallow(
+ const wrapper = mount(