diff --git a/MANIFEST.in b/MANIFEST.in
index e57373a46e545..a1b3ffac9b566 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,7 +1,5 @@
recursive-include superset/templates *
recursive-include superset/static *
-recursive-exclude superset/static/assets/node_modules *
-recursive-include superset/static/assets/node_modules/font-awesome *
recursive-exclude superset/static/docs *
recursive-exclude superset/static/spec *
recursive-exclude tests *
diff --git a/setup.py b/setup.py
index ad86b08959ae0..afc767c2c5cd6 100644
--- a/setup.py
+++ b/setup.py
@@ -46,6 +46,7 @@ def get_git_sha():
'celery==3.1.25',
'colorama==0.3.9',
'cryptography==1.9',
+ 'flask==0.12.2',
'flask-appbuilder==1.9.1',
'flask-cache==0.13.1',
'flask-migrate==2.0.3',
diff --git a/superset/__init__.py b/superset/__init__.py
index fceff86159ff8..9576458804337 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -32,19 +32,21 @@
app.config.from_object(CONFIG_MODULE)
conf = app.config
+# Handling manifest file logic at app start
+MANIFEST_FILE = APP_DIR + '/static/assets/dist/manifest.json'
+get_manifest_file = lambda x: x
+manifest = {}
+try:
+ with open(MANIFEST_FILE, 'r') as f:
+ manifest = json.load(f)
+ get_manifest_file = lambda x: '/static/assets/dist/' + manifest.get(x, '')
+except Exception:
+ print("no manifest file found at " + MANIFEST_FILE)
+
@app.context_processor
def get_js_manifest():
- manifest = {}
- try:
- with open(APP_DIR + '/static/assets/dist/manifest.json', 'r') as f:
- manifest = json.load(f)
- except Exception as e:
- print(
- "no manifest file found at " +
- APP_DIR + "/static/assets/dist/manifest.json"
- )
- return dict(js_manifest=manifest)
+ return dict(js_manifest=get_manifest_file)
for bp in conf.get('BLUEPRINTS'):
@@ -69,7 +71,7 @@ def get_js_manifest():
if conf.get('WTF_CSRF_ENABLED'):
csrf = CSRFProtect(app)
-utils.pessimistic_connection_handling(db.engine.pool)
+utils.pessimistic_connection_handling(db.engine)
cache = utils.setup_cache(app, conf.get('CACHE_CONFIG'))
tables_cache = utils.setup_cache(app, conf.get('TABLE_NAMES_CACHE_CONFIG'))
diff --git a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx
index dce820cd677a5..56a66d3a66ea0 100644
--- a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx
+++ b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx
@@ -13,13 +13,18 @@ import { getExploreUrl } from '../../explore/exploreUtils';
import * as actions from '../actions';
import { VISUALIZE_VALIDATION_ERRORS } from '../constants';
import { QUERY_TIMEOUT_THRESHOLD } from '../../constants';
+import visTypes from '../../explore/stores/visTypes';
-const CHART_TYPES = [
- { value: 'dist_bar', label: 'Distribution - Bar Chart', requiresTime: false },
- { value: 'pie', label: 'Pie Chart', requiresTime: false },
- { value: 'line', label: 'Time Series - Line Chart', requiresTime: true },
- { value: 'bar', label: 'Time Series - Bar Chart', requiresTime: true },
-];
+const CHART_TYPES = Object.keys(visTypes)
+ .filter(typeName => !!visTypes[typeName].showOnExplore)
+ .map((typeName) => {
+ const vis = visTypes[typeName];
+ return {
+ value: typeName,
+ label: vis.label,
+ requiresTime: !!vis.requiresTime,
+ };
+ });
const propTypes = {
actions: PropTypes.object.isRequired,
diff --git a/superset/assets/javascripts/SqlLab/index.jsx b/superset/assets/javascripts/SqlLab/index.jsx
index ba09924720177..4e2eae898c6db 100644
--- a/superset/assets/javascripts/SqlLab/index.jsx
+++ b/superset/assets/javascripts/SqlLab/index.jsx
@@ -10,7 +10,7 @@ import { initJQueryAjax } from '../modules/utils';
import App from './components/App';
import { appSetup } from '../common';
-import './main.css';
+import './main.less';
import '../../stylesheets/reactable-pagination.css';
import '../components/FilterableTable/FilterableTableStyles.css';
diff --git a/superset/assets/javascripts/SqlLab/main.css b/superset/assets/javascripts/SqlLab/main.less
similarity index 99%
rename from superset/assets/javascripts/SqlLab/main.css
rename to superset/assets/javascripts/SqlLab/main.less
index ad2bb37c0e3e6..d5dab4c03cc09 100644
--- a/superset/assets/javascripts/SqlLab/main.css
+++ b/superset/assets/javascripts/SqlLab/main.less
@@ -161,7 +161,6 @@ div.Workspace {
margin: 0px;
border: none;
font-size: 12px;
- line-height: @line-height-base;
background-color: transparent !important;
}
diff --git a/superset/assets/javascripts/explore/actions/chartActions.js b/superset/assets/javascripts/explore/actions/chartActions.js
new file mode 100644
index 0000000000000..6c9291dc41ece
--- /dev/null
+++ b/superset/assets/javascripts/explore/actions/chartActions.js
@@ -0,0 +1,70 @@
+import { getExploreUrl } from '../exploreUtils';
+import { getFormDataFromControls } from '../stores/store';
+import { QUERY_TIMEOUT_THRESHOLD } from '../../constants';
+import { triggerQuery } from './exploreActions';
+
+const $ = window.$ = require('jquery');
+
+export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
+export function chartUpdateStarted(queryRequest, latestQueryFormData) {
+ return { type: CHART_UPDATE_STARTED, queryRequest, latestQueryFormData };
+}
+
+export const CHART_UPDATE_SUCCEEDED = 'CHART_UPDATE_SUCCEEDED';
+export function chartUpdateSucceeded(queryResponse) {
+ return { type: CHART_UPDATE_SUCCEEDED, queryResponse };
+}
+
+export const CHART_UPDATE_STOPPED = 'CHART_UPDATE_STOPPED';
+export function chartUpdateStopped(queryRequest) {
+ if (queryRequest) {
+ queryRequest.abort();
+ }
+ return { type: CHART_UPDATE_STOPPED };
+}
+
+export const CHART_UPDATE_TIMEOUT = 'CHART_UPDATE_TIMEOUT';
+export function chartUpdateTimeout(statusText) {
+ return { type: CHART_UPDATE_TIMEOUT, statusText };
+}
+
+export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED';
+export function chartUpdateFailed(queryResponse) {
+ return { type: CHART_UPDATE_FAILED, queryResponse };
+}
+
+export const UPDATE_CHART_STATUS = 'UPDATE_CHART_STATUS';
+export function updateChartStatus(status) {
+ return { type: UPDATE_CHART_STATUS, status };
+}
+
+export const CHART_RENDERING_FAILED = 'CHART_RENDERING_FAILED';
+export function chartRenderingFailed(error) {
+ return { type: CHART_RENDERING_FAILED, error };
+}
+
+export const RUN_QUERY = 'RUN_QUERY';
+export function runQuery(formData, force = false) {
+ return function (dispatch, getState) {
+ const { explore } = getState();
+ const lastQueryFormData = getFormDataFromControls(explore.controls);
+ const url = getExploreUrl(formData, 'json', force);
+ const queryRequest = $.ajax({
+ url,
+ dataType: 'json',
+ success(queryResponse) {
+ dispatch(chartUpdateSucceeded(queryResponse));
+ },
+ error(err) {
+ if (err.statusText === 'timeout') {
+ dispatch(chartUpdateTimeout(err.statusText));
+ } else if (err.statusText !== 'abort') {
+ dispatch(chartUpdateFailed(err.responseJSON));
+ }
+ },
+ timeout: QUERY_TIMEOUT_THRESHOLD,
+ });
+ dispatch(chartUpdateStarted(queryRequest, lastQueryFormData));
+ dispatch(triggerQuery(false));
+ };
+}
diff --git a/superset/assets/javascripts/explore/actions/exploreActions.js b/superset/assets/javascripts/explore/actions/exploreActions.js
index d45acd5834b9e..32fa3c5b4745f 100644
--- a/superset/assets/javascripts/explore/actions/exploreActions.js
+++ b/superset/assets/javascripts/explore/actions/exploreActions.js
@@ -1,6 +1,4 @@
/* eslint camelcase: 0 */
-import { getExploreUrl } from '../exploreUtils';
-import { QUERY_TIMEOUT_THRESHOLD } from '../../constants';
const $ = window.$ = require('jquery');
@@ -37,8 +35,8 @@ export function resetControls() {
}
export const TRIGGER_QUERY = 'TRIGGER_QUERY';
-export function triggerQuery() {
- return { type: TRIGGER_QUERY };
+export function triggerQuery(value = true) {
+ return { type: TRIGGER_QUERY, value };
}
export function fetchDatasourceMetadata(datasourceKey, alsoTriggerQuery = false) {
@@ -95,39 +93,6 @@ export function setControlValue(controlName, value, validationErrors) {
return { type: SET_FIELD_VALUE, controlName, value, validationErrors };
}
-export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
-export function chartUpdateStarted(queryRequest) {
- return { type: CHART_UPDATE_STARTED, queryRequest };
-}
-
-export const CHART_UPDATE_SUCCEEDED = 'CHART_UPDATE_SUCCEEDED';
-export function chartUpdateSucceeded(queryResponse) {
- return { type: CHART_UPDATE_SUCCEEDED, queryResponse };
-}
-
-export const CHART_UPDATE_STOPPED = 'CHART_UPDATE_STOPPED';
-export function chartUpdateStopped(queryRequest) {
- if (queryRequest) {
- queryRequest.abort();
- }
- return { type: CHART_UPDATE_STOPPED };
-}
-
-export const CHART_UPDATE_TIMEOUT = 'CHART_UPDATE_TIMEOUT';
-export function chartUpdateTimeout(statusText) {
- return { type: CHART_UPDATE_TIMEOUT, statusText };
-}
-
-export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED';
-export function chartUpdateFailed(queryResponse) {
- return { type: CHART_UPDATE_FAILED, queryResponse };
-}
-
-export const CHART_RENDERING_FAILED = 'CHART_RENDERING_FAILED';
-export function chartRenderingFailed(error) {
- return { type: CHART_RENDERING_FAILED, error };
-}
-
export const UPDATE_EXPLORE_ENDPOINTS = 'UPDATE_EXPLORE_ENDPOINTS';
export function updateExploreEndpoints(jsonUrl, csvUrl, standaloneUrl) {
return { type: UPDATE_EXPLORE_ENDPOINTS, jsonUrl, csvUrl, standaloneUrl };
@@ -143,95 +108,11 @@ export function removeChartAlert() {
return { type: REMOVE_CHART_ALERT };
}
-export const FETCH_DASHBOARDS_SUCCEEDED = 'FETCH_DASHBOARDS_SUCCEEDED';
-export function fetchDashboardsSucceeded(choices) {
- return { type: FETCH_DASHBOARDS_SUCCEEDED, choices };
-}
-
-export const FETCH_DASHBOARDS_FAILED = 'FETCH_DASHBOARDS_FAILED';
-export function fetchDashboardsFailed(userId) {
- return { type: FETCH_DASHBOARDS_FAILED, userId };
-}
-
-export function fetchDashboards(userId) {
- return function (dispatch) {
- const url = '/dashboardmodelviewasync/api/read?_flt_0_owners=' + userId;
- $.ajax({
- type: 'GET',
- url,
- success: (data) => {
- const choices = [];
- for (let i = 0; i < data.pks.length; i++) {
- choices.push({ value: data.pks[i], label: data.result[i].dashboard_title });
- }
- dispatch(fetchDashboardsSucceeded(choices));
- },
- error: () => {
- dispatch(fetchDashboardsFailed(userId));
- },
- });
- };
-}
-
-export const SAVE_SLICE_FAILED = 'SAVE_SLICE_FAILED';
-export function saveSliceFailed() {
- return { type: SAVE_SLICE_FAILED };
-}
-export const SAVE_SLICE_SUCCESS = 'SAVE_SLICE_SUCCESS';
-export function saveSliceSuccess(data) {
- return { type: SAVE_SLICE_SUCCESS, data };
-}
-
-export const REMOVE_SAVE_MODAL_ALERT = 'REMOVE_SAVE_MODAL_ALERT';
-export function removeSaveModalAlert() {
- return { type: REMOVE_SAVE_MODAL_ALERT };
-}
-
-export function saveSlice(url) {
- return function (dispatch) {
- return $.get(url, (data, status) => {
- if (status === 'success') {
- dispatch(saveSliceSuccess(data));
- } else {
- dispatch(saveSliceFailed());
- }
- });
- };
-}
-
export const UPDATE_CHART_TITLE = 'UPDATE_CHART_TITLE';
export function updateChartTitle(slice_name) {
return { type: UPDATE_CHART_TITLE, slice_name };
}
-export const UPDATE_CHART_STATUS = 'UPDATE_CHART_STATUS';
-export function updateChartStatus(status) {
- return { type: UPDATE_CHART_STATUS, status };
-}
-
-export const RUN_QUERY = 'RUN_QUERY';
-export function runQuery(formData, force = false) {
- return function (dispatch) {
- const url = getExploreUrl(formData, 'json', force);
- const queryRequest = $.ajax({
- url,
- dataType: 'json',
- success(queryResponse) {
- dispatch(chartUpdateSucceeded(queryResponse));
- },
- error(err) {
- if (err.statusText === 'timeout') {
- dispatch(chartUpdateTimeout(err.statusText));
- } else if (err.statusText !== 'abort') {
- dispatch(chartUpdateFailed(err.responseJSON));
- }
- },
- timeout: QUERY_TIMEOUT_THRESHOLD,
- });
- dispatch(chartUpdateStarted(queryRequest));
- };
-}
-
export const RENDER_TRIGGERED = 'RENDER_TRIGGERED';
export function renderTriggered() {
return { type: RENDER_TRIGGERED };
diff --git a/superset/assets/javascripts/explore/actions/saveModalActions.js b/superset/assets/javascripts/explore/actions/saveModalActions.js
new file mode 100644
index 0000000000000..b1111287f288c
--- /dev/null
+++ b/superset/assets/javascripts/explore/actions/saveModalActions.js
@@ -0,0 +1,57 @@
+const $ = window.$ = require('jquery');
+
+export const FETCH_DASHBOARDS_SUCCEEDED = 'FETCH_DASHBOARDS_SUCCEEDED';
+export function fetchDashboardsSucceeded(choices) {
+ return { type: FETCH_DASHBOARDS_SUCCEEDED, choices };
+}
+
+export const FETCH_DASHBOARDS_FAILED = 'FETCH_DASHBOARDS_FAILED';
+export function fetchDashboardsFailed(userId) {
+ return { type: FETCH_DASHBOARDS_FAILED, userId };
+}
+
+export function fetchDashboards(userId) {
+ return function (dispatch) {
+ const url = '/dashboardmodelviewasync/api/read?_flt_0_owners=' + userId;
+ return $.ajax({
+ type: 'GET',
+ url,
+ success: (data) => {
+ const choices = [];
+ for (let i = 0; i < data.pks.length; i++) {
+ choices.push({ value: data.pks[i], label: data.result[i].dashboard_title });
+ }
+ dispatch(fetchDashboardsSucceeded(choices));
+ },
+ error: () => {
+ dispatch(fetchDashboardsFailed(userId));
+ },
+ });
+ };
+}
+
+export const SAVE_SLICE_FAILED = 'SAVE_SLICE_FAILED';
+export function saveSliceFailed() {
+ return { type: SAVE_SLICE_FAILED };
+}
+export const SAVE_SLICE_SUCCESS = 'SAVE_SLICE_SUCCESS';
+export function saveSliceSuccess(data) {
+ return { type: SAVE_SLICE_SUCCESS, data };
+}
+
+export const REMOVE_SAVE_MODAL_ALERT = 'REMOVE_SAVE_MODAL_ALERT';
+export function removeSaveModalAlert() {
+ return { type: REMOVE_SAVE_MODAL_ALERT };
+}
+
+export function saveSlice(url) {
+ return function (dispatch) {
+ return $.get(url, (data, status) => {
+ if (status === 'success') {
+ dispatch(saveSliceSuccess(data));
+ } else {
+ dispatch(saveSliceFailed());
+ }
+ });
+ };
+}
diff --git a/superset/assets/javascripts/explore/components/ChartContainer.jsx b/superset/assets/javascripts/explore/components/ChartContainer.jsx
index ab2be2fcdf24c..3e93b9e6a4be7 100644
--- a/superset/assets/javascripts/explore/components/ChartContainer.jsx
+++ b/superset/assets/javascripts/explore/components/ChartContainer.jsx
@@ -322,29 +322,29 @@ class ChartContainer extends React.PureComponent {
ChartContainer.propTypes = propTypes;
-function mapStateToProps(state) {
- const formData = getFormDataFromControls(state.controls);
+function mapStateToProps({ explore, chart }) {
+ const formData = getFormDataFromControls(explore.controls);
return {
- alert: state.chartAlert,
- can_overwrite: state.can_overwrite,
- can_download: state.can_download,
- chartStatus: state.chartStatus,
- chartUpdateEndTime: state.chartUpdateEndTime,
- chartUpdateStartTime: state.chartUpdateStartTime,
- datasource: state.datasource,
- column_formats: state.datasource ? state.datasource.column_formats : null,
- containerId: state.slice ? `slice-container-${state.slice.slice_id}` : 'slice-container',
+ alert: explore.chartAlert,
+ can_overwrite: explore.can_overwrite,
+ can_download: explore.can_download,
+ datasource: explore.datasource,
+ column_formats: explore.datasource ? explore.datasource.column_formats : null,
+ containerId: explore.slice ? `slice-container-${explore.slice.slice_id}` : 'slice-container',
formData,
- latestQueryFormData: state.latestQueryFormData,
- isStarred: state.isStarred,
- queryResponse: state.queryResponse,
- slice: state.slice,
- standalone: state.standalone,
+ isStarred: explore.isStarred,
+ slice: explore.slice,
+ standalone: explore.standalone,
table_name: formData.datasource_name,
viz_type: formData.viz_type,
- triggerRender: state.triggerRender,
- datasourceType: state.datasource.type,
- datasourceId: state.datasource_id,
+ triggerRender: explore.triggerRender,
+ datasourceType: explore.datasource.type,
+ datasourceId: explore.datasource_id,
+ chartStatus: chart.chartStatus,
+ chartUpdateEndTime: chart.chartUpdateEndTime,
+ chartUpdateStartTime: chart.chartUpdateStartTime,
+ latestQueryFormData: chart.latestQueryFormData,
+ queryResponse: chart.queryResponse,
};
}
diff --git a/superset/assets/javascripts/explore/components/ControlPanelsContainer.jsx b/superset/assets/javascripts/explore/components/ControlPanelsContainer.jsx
index e3b29855a8075..8a8c2d8802b80 100644
--- a/superset/assets/javascripts/explore/components/ControlPanelsContainer.jsx
+++ b/superset/assets/javascripts/explore/components/ControlPanelsContainer.jsx
@@ -96,12 +96,12 @@ class ControlPanelsContainer extends React.Component {
ControlPanelsContainer.propTypes = propTypes;
-function mapStateToProps(state) {
+function mapStateToProps({ explore }) {
return {
- alert: state.controlPanelAlert,
- isDatasourceMetaLoading: state.isDatasourceMetaLoading,
- controls: state.controls,
- exploreState: state,
+ alert: explore.controlPanelAlert,
+ isDatasourceMetaLoading: explore.isDatasourceMetaLoading,
+ controls: explore.controls,
+ exploreState: explore,
};
}
diff --git a/superset/assets/javascripts/explore/components/ExploreViewContainer.jsx b/superset/assets/javascripts/explore/components/ExploreViewContainer.jsx
index ae94f6a02efcc..bb96dbc3a3270 100644
--- a/superset/assets/javascripts/explore/components/ExploreViewContainer.jsx
+++ b/superset/assets/javascripts/explore/components/ExploreViewContainer.jsx
@@ -8,12 +8,15 @@ import ControlPanelsContainer from './ControlPanelsContainer';
import SaveModal from './SaveModal';
import QueryAndSaveBtns from './QueryAndSaveBtns';
import { getExploreUrl } from '../exploreUtils';
-import * as actions from '../actions/exploreActions';
import { getFormDataFromControls } from '../stores/store';
+import * as exploreActions from '../actions/exploreActions';
+import * as saveModalActions from '../actions/saveModalActions';
+import * as chartActions from '../actions/chartActions';
const propTypes = {
actions: PropTypes.object.isRequired,
datasource_type: PropTypes.string.isRequired,
+ isDatasourceMetaLoading: PropTypes.bool.isRequired,
chartStatus: PropTypes.string,
controls: PropTypes.object.isRequired,
forcedHeight: PropTypes.string,
@@ -85,7 +88,6 @@ class ExploreViewContainer extends React.Component {
return `${window.innerHeight - navHeight}px`;
}
-
triggerQueryIfNeeded() {
if (this.props.triggerQuery && !this.hasErrors()) {
this.props.actions.runQuery(this.props.form_data);
@@ -172,7 +174,9 @@ class ExploreViewContainer extends React.Component {
@@ -186,21 +190,23 @@ class ExploreViewContainer extends React.Component {
ExploreViewContainer.propTypes = propTypes;
-function mapStateToProps(state) {
- const form_data = getFormDataFromControls(state.controls);
+function mapStateToProps({ explore, chart }) {
+ const form_data = getFormDataFromControls(explore.controls);
return {
- chartStatus: state.chartStatus,
- datasource_type: state.datasource.type,
- controls: state.controls,
+ isDatasourceMetaLoading: explore.isDatasourceMetaLoading,
+ datasource_type: explore.datasource.type,
+ controls: explore.controls,
form_data,
- standalone: state.standalone,
- triggerQuery: state.triggerQuery,
- forcedHeight: state.forced_height,
- queryRequest: state.queryRequest,
+ standalone: explore.standalone,
+ triggerQuery: explore.triggerQuery,
+ forcedHeight: explore.forced_height,
+ queryRequest: chart.queryRequest,
+ chartStatus: chart.chartStatus,
};
}
function mapDispatchToProps(dispatch) {
+ const actions = Object.assign({}, exploreActions, saveModalActions, chartActions);
return {
actions: bindActionCreators(actions, dispatch),
};
diff --git a/superset/assets/javascripts/explore/components/SaveModal.jsx b/superset/assets/javascripts/explore/components/SaveModal.jsx
index 4dbff36acfea6..beb07b27ea4d2 100644
--- a/superset/assets/javascripts/explore/components/SaveModal.jsx
+++ b/superset/assets/javascripts/explore/components/SaveModal.jsx
@@ -1,10 +1,11 @@
/* eslint camelcase: 0 */
import React from 'react';
import PropTypes from 'prop-types';
-import $ from 'jquery';
+import { connect } from 'react-redux';
+
import { Modal, Alert, Button, Radio } from 'react-bootstrap';
import Select from 'react-select';
-import { connect } from 'react-redux';
+import { getExploreUrl } from '../exploreUtils';
const propTypes = {
can_overwrite: PropTypes.bool,
@@ -102,12 +103,7 @@ class SaveModal extends React.Component {
}
sliceParams.goto_dash = gotodash;
- const baseUrl = `/superset/explore/${this.props.datasource.type}/${this.props.datasource.id}/`;
- sliceParams.datasource_name = this.props.datasource.name;
-
- const saveUrl = `${baseUrl}?form_data=` +
- `${encodeURIComponent(JSON.stringify(this.props.form_data))}` +
- `&${$.param(sliceParams, true)}`;
+ const saveUrl = getExploreUrl(this.props.form_data, 'base', false, null, sliceParams);
this.props.actions.saveSlice(saveUrl)
.then((data) => {
// Go to new slice url or dashboard url
@@ -234,14 +230,14 @@ class SaveModal extends React.Component {
SaveModal.propTypes = propTypes;
-function mapStateToProps(state) {
+function mapStateToProps({ explore, saveModal }) {
return {
- datasource: state.datasource,
- slice: state.slice,
- can_overwrite: state.can_overwrite,
- user_id: state.user_id,
- dashboards: state.dashboards,
- alert: state.saveModalAlert,
+ datasource: explore.datasource,
+ slice: explore.slice,
+ can_overwrite: explore.can_overwrite,
+ user_id: explore.user_id,
+ dashboards: saveModal.dashboards,
+ alert: explore.saveModalAlert,
};
}
diff --git a/superset/assets/javascripts/explore/index.jsx b/superset/assets/javascripts/explore/index.jsx
index 0fe4fcaba9524..2f6e898ee276f 100644
--- a/superset/assets/javascripts/explore/index.jsx
+++ b/superset/assets/javascripts/explore/index.jsx
@@ -11,7 +11,8 @@ import AlertsWrapper from '../components/AlertsWrapper';
import { getControlsState, getFormDataFromControls } from './stores/store';
import { initJQueryAjax } from '../modules/utils';
import ExploreViewContainer from './components/ExploreViewContainer';
-import { exploreReducer } from './reducers/exploreReducer';
+import rootReducer from './reducers/index';
+
import { appSetup } from '../common';
import './main.css';
import '../../stylesheets/reactable-pagination.css';
@@ -19,7 +20,7 @@ import '../../stylesheets/reactable-pagination.css';
appSetup();
initJQueryAjax();
-const exploreViewContainer = document.getElementById('js-explore-view-container');
+const exploreViewContainer = document.getElementById('app');
const bootstrapData = JSON.parse(exploreViewContainer.getAttribute('data-bootstrap'));
const controls = getControlsState(bootstrapData, bootstrapData.form_data);
delete bootstrapData.form_data;
@@ -28,23 +29,30 @@ delete bootstrapData.form_data;
// Initial state
const bootstrappedState = Object.assign(
bootstrapData, {
- chartStatus: null,
- chartUpdateEndTime: null,
- chartUpdateStartTime: now(),
- dashboards: [],
controls,
- latestQueryFormData: getFormDataFromControls(controls),
filterColumnOpts: [],
isDatasourceMetaLoading: false,
isStarred: false,
- queryResponse: null,
triggerQuery: true,
triggerRender: false,
alert: null,
},
);
-const store = createStore(exploreReducer, bootstrappedState,
+const initState = {
+ chart: {
+ chartStatus: null,
+ chartUpdateEndTime: null,
+ chartUpdateStartTime: now(),
+ latestQueryFormData: getFormDataFromControls(controls),
+ queryResponse: null,
+ },
+ saveModal: {
+ dashboards: [],
+ },
+ explore: bootstrappedState,
+};
+const store = createStore(rootReducer, initState,
compose(applyMiddleware(thunk), initEnhancer(false)),
);
diff --git a/superset/assets/javascripts/explore/reducers/chartReducer.js b/superset/assets/javascripts/explore/reducers/chartReducer.js
new file mode 100644
index 0000000000000..c41771b44c313
--- /dev/null
+++ b/superset/assets/javascripts/explore/reducers/chartReducer.js
@@ -0,0 +1,72 @@
+/* eslint camelcase: 0 */
+import { now } from '../../modules/dates';
+import * as actions from '../actions/chartActions';
+import { QUERY_TIMEOUT_THRESHOLD } from '../../constants';
+
+export default function chartReducer(state = {}, action) {
+ const actionHandlers = {
+ [actions.CHART_UPDATE_SUCCEEDED]() {
+ return Object.assign(
+ {},
+ state,
+ {
+ chartStatus: 'success',
+ queryResponse: action.queryResponse,
+ },
+ );
+ },
+ [actions.CHART_UPDATE_STARTED]() {
+ return Object.assign({}, state,
+ {
+ chartStatus: 'loading',
+ chartUpdateEndTime: null,
+ chartUpdateStartTime: now(),
+ queryRequest: action.queryRequest,
+ latestQueryFormData: action.latestQueryFormData,
+ });
+ },
+ [actions.CHART_UPDATE_STOPPED]() {
+ return Object.assign({}, state,
+ {
+ chartStatus: 'stopped',
+ chartAlert: 'Updating chart was stopped',
+ });
+ },
+ [actions.CHART_RENDERING_FAILED]() {
+ return Object.assign({}, state, {
+ chartStatus: 'failed',
+ chartAlert: 'An error occurred while rendering the visualization: ' + action.error,
+ });
+ },
+ [actions.CHART_UPDATE_TIMEOUT]() {
+ return Object.assign({}, state, {
+ chartStatus: 'failed',
+ chartAlert: '
Query timeout - visualization query are set to timeout at ' +
+ `${QUERY_TIMEOUT_THRESHOLD / 1000} seconds. ` +
+ 'Perhaps your data has grown, your database is under unusual load, ' +
+ 'or you are simply querying a data source that is to large to be processed within the timeout range. ' +
+ 'If that is the case, we recommend that you summarize your data further.',
+ });
+ },
+ [actions.CHART_UPDATE_FAILED]() {
+ return Object.assign({}, state, {
+ chartStatus: 'failed',
+ chartAlert: action.queryResponse ? action.queryResponse.error : 'Network error.',
+ chartUpdateEndTime: now(),
+ queryResponse: action.queryResponse,
+ });
+ },
+ [actions.UPDATE_CHART_STATUS]() {
+ const newState = Object.assign({}, state, { chartStatus: action.status });
+ if (action.status === 'success' || action.status === 'failed') {
+ newState.chartUpdateEndTime = now();
+ }
+ return newState;
+ },
+ };
+
+ if (action.type in actionHandlers) {
+ return actionHandlers[action.type]();
+ }
+ return state;
+}
diff --git a/superset/assets/javascripts/explore/reducers/exploreReducer.js b/superset/assets/javascripts/explore/reducers/exploreReducer.js
index 96e36e3765754..bc1072f49163f 100644
--- a/superset/assets/javascripts/explore/reducers/exploreReducer.js
+++ b/superset/assets/javascripts/explore/reducers/exploreReducer.js
@@ -1,23 +1,18 @@
/* eslint camelcase: 0 */
import { getControlsState, getFormDataFromControls } from '../stores/store';
import * as actions from '../actions/exploreActions';
-import { now } from '../../modules/dates';
-import { QUERY_TIMEOUT_THRESHOLD } from '../../constants';
-export const exploreReducer = function (state, action) {
+export default function exploreReducer(state = {}, action) {
const actionHandlers = {
[actions.TOGGLE_FAVE_STAR]() {
return Object.assign({}, state, { isStarred: action.isStarred });
},
-
[actions.FETCH_DATASOURCE_STARTED]() {
return Object.assign({}, state, { isDatasourceMetaLoading: true });
},
-
[actions.FETCH_DATASOURCE_SUCCEEDED]() {
return Object.assign({}, state, { isDatasourceMetaLoading: false });
},
-
[actions.FETCH_DATASOURCE_FAILED]() {
// todo(alanna) handle failure/error state
return Object.assign({}, state,
@@ -29,16 +24,25 @@ export const exploreReducer = function (state, action) {
[actions.SET_DATASOURCE]() {
return Object.assign({}, state, { datasource: action.datasource });
},
- [actions.REMOVE_CONTROL_PANEL_ALERT]() {
- return Object.assign({}, state, { controlPanelAlert: null });
+ [actions.FETCH_DATASOURCES_STARTED]() {
+ return Object.assign({}, state, { isDatasourcesLoading: true });
},
- [actions.FETCH_DASHBOARDS_SUCCEEDED]() {
- return Object.assign({}, state, { dashboards: action.choices });
+ [actions.FETCH_DATASOURCES_SUCCEEDED]() {
+ return Object.assign({}, state, { isDatasourcesLoading: false });
},
-
- [actions.FETCH_DASHBOARDS_FAILED]() {
+ [actions.FETCH_DATASOURCES_FAILED]() {
+ // todo(alanna) handle failure/error state
return Object.assign({}, state,
- { saveModalAlert: `fetching dashboards failed for ${action.userId}` });
+ {
+ isDatasourcesLoading: false,
+ controlPanelAlert: action.error,
+ });
+ },
+ [actions.SET_DATASOURCES]() {
+ return Object.assign({}, state, { datasources: action.datasources });
+ },
+ [actions.REMOVE_CONTROL_PANEL_ALERT]() {
+ return Object.assign({}, state, { controlPanelAlert: null });
},
[actions.SET_FIELD_VALUE]() {
const controls = Object.assign({}, state.controls);
@@ -52,70 +56,11 @@ export const exploreReducer = function (state, action) {
}
return Object.assign({}, state, changes);
},
- [actions.CHART_UPDATE_SUCCEEDED]() {
- return Object.assign(
- {},
- state,
- {
- chartStatus: 'success',
- queryResponse: action.queryResponse,
- },
- );
- },
- [actions.CHART_UPDATE_STARTED]() {
- return Object.assign({}, state,
- {
- chartStatus: 'loading',
- chartUpdateEndTime: null,
- chartUpdateStartTime: now(),
- triggerQuery: false,
- queryRequest: action.queryRequest,
- latestQueryFormData: getFormDataFromControls(state.controls),
- });
- },
- [actions.CHART_UPDATE_STOPPED]() {
- return Object.assign({}, state,
- {
- chartStatus: 'stopped',
- chartAlert: 'Updating chart was stopped',
- });
- },
- [actions.CHART_RENDERING_FAILED]() {
- return Object.assign({}, state, {
- chartStatus: 'failed',
- chartAlert: 'An error occurred while rendering the visualization: ' + action.error,
- });
- },
[actions.TRIGGER_QUERY]() {
return Object.assign({}, state, {
- triggerQuery: true,
+ triggerQuery: action.value,
});
},
- [actions.CHART_UPDATE_TIMEOUT]() {
- return Object.assign({}, state, {
- chartStatus: 'failed',
- chartAlert: '
Query timeout - visualization query are set to timeout at ' +
- `${QUERY_TIMEOUT_THRESHOLD / 1000} seconds. ` +
- 'Perhaps your data has grown, your database is under unusual load, ' +
- 'or you are simply querying a data source that is to large to be processed within the timeout range. ' +
- 'If that is the case, we recommend that you summarize your data further.',
- });
- },
- [actions.CHART_UPDATE_FAILED]() {
- return Object.assign({}, state, {
- chartStatus: 'failed',
- chartAlert: action.queryResponse ? action.queryResponse.error : 'Network error.',
- chartUpdateEndTime: now(),
- queryResponse: action.queryResponse,
- });
- },
- [actions.UPDATE_CHART_STATUS]() {
- const newState = Object.assign({}, state, { chartStatus: action.status });
- if (action.status === 'success' || action.status === 'failed') {
- newState.chartUpdateEndTime = now();
- }
- return newState;
- },
[actions.UPDATE_CHART_TITLE]() {
const updatedSlice = Object.assign({}, state.slice, { slice_name: action.slice_name });
return Object.assign({}, state, { slice: updatedSlice });
@@ -126,15 +71,6 @@ export const exploreReducer = function (state, action) {
}
return state;
},
- [actions.SAVE_SLICE_FAILED]() {
- return Object.assign({}, state, { saveModalAlert: 'Failed to save slice' });
- },
- [actions.SAVE_SLICE_SUCCESS](data) {
- return Object.assign({}, state, { data });
- },
- [actions.REMOVE_SAVE_MODAL_ALERT]() {
- return Object.assign({}, state, { saveModalAlert: null });
- },
[actions.RESET_FIELDS]() {
const controls = getControlsState(state, getFormDataFromControls(state.controls));
return Object.assign({}, state, { controls });
@@ -147,4 +83,4 @@ export const exploreReducer = function (state, action) {
return actionHandlers[action.type]();
}
return state;
-};
+}
diff --git a/superset/assets/javascripts/explore/reducers/index.js b/superset/assets/javascripts/explore/reducers/index.js
new file mode 100644
index 0000000000000..0d5acb04c7e88
--- /dev/null
+++ b/superset/assets/javascripts/explore/reducers/index.js
@@ -0,0 +1,11 @@
+import { combineReducers } from 'redux';
+
+import chart from './chartReducer';
+import saveModal from './saveModalReducer';
+import explore from './exploreReducer';
+
+export default combineReducers({
+ chart,
+ saveModal,
+ explore,
+});
diff --git a/superset/assets/javascripts/explore/reducers/saveModalReducer.js b/superset/assets/javascripts/explore/reducers/saveModalReducer.js
new file mode 100644
index 0000000000000..912d5315f3049
--- /dev/null
+++ b/superset/assets/javascripts/explore/reducers/saveModalReducer.js
@@ -0,0 +1,28 @@
+/* eslint camelcase: 0 */
+import * as actions from '../actions/saveModalActions';
+
+export default function saveModalReducer(state = {}, action) {
+ const actionHandlers = {
+ [actions.FETCH_DASHBOARDS_SUCCEEDED]() {
+ return Object.assign({}, state, { dashboards: action.choices });
+ },
+ [actions.FETCH_DASHBOARDS_FAILED]() {
+ return Object.assign({}, state,
+ { saveModalAlert: `fetching dashboards failed for ${action.userId}` });
+ },
+ [actions.SAVE_SLICE_FAILED]() {
+ return Object.assign({}, state, { saveModalAlert: 'Failed to save slice' });
+ },
+ [actions.SAVE_SLICE_SUCCESS](data) {
+ return Object.assign({}, state, { data });
+ },
+ [actions.REMOVE_SAVE_MODAL_ALERT]() {
+ return Object.assign({}, state, { saveModalAlert: null });
+ },
+ };
+
+ if (action.type in actionHandlers) {
+ return actionHandlers[action.type]();
+ }
+ return state;
+}
diff --git a/superset/assets/javascripts/explore/stores/visTypes.js b/superset/assets/javascripts/explore/stores/visTypes.js
index 1df8e11c7267e..e937b036ab2db 100644
--- a/superset/assets/javascripts/explore/stores/visTypes.js
+++ b/superset/assets/javascripts/explore/stores/visTypes.js
@@ -78,6 +78,7 @@ export const sections = {
export const visTypes = {
dist_bar: {
label: 'Distribution - Bar Chart',
+ showOnExplore: true,
controlPanelSections: [
{
label: 'Chart Options',
@@ -108,6 +109,7 @@ export const visTypes = {
pie: {
label: 'Pie Chart',
+ showOnExplore: true,
controlPanelSections: [
{
label: null,
@@ -124,6 +126,7 @@ export const visTypes = {
line: {
label: 'Time Series - Line Chart',
+ showOnExplore: true,
requiresTime: true,
controlPanelSections: [
sections.NVD3TimeSeries[0],
@@ -194,6 +197,7 @@ export const visTypes = {
bar: {
label: 'Time Series - Bar Chart',
+ showOnExplore: true,
requiresTime: true,
controlPanelSections: [
sections.NVD3TimeSeries[0],
diff --git a/superset/assets/javascripts/css-theme.js b/superset/assets/javascripts/theme.js
similarity index 70%
rename from superset/assets/javascripts/css-theme.js
rename to superset/assets/javascripts/theme.js
index 8fab234f65f6f..68a7a8ac5f021 100644
--- a/superset/assets/javascripts/css-theme.js
+++ b/superset/assets/javascripts/theme.js
@@ -1,2 +1,3 @@
import '../stylesheets/less/index.less';
import '../stylesheets/react-select/select.less';
+import '../stylesheets/superset.less';
diff --git a/superset/assets/package.json b/superset/assets/package.json
index 1422492bfea58..2dde6b337a95d 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -108,6 +108,7 @@
"eslint-plugin-jsx-a11y": "^5.0.3",
"eslint-plugin-react": "^7.0.1",
"exports-loader": "^0.6.3",
+ "extract-text-webpack-plugin": "2.1.2",
"file-loader": "^0.11.1",
"github-changes": "^1.0.4",
"ignore-styles": "^5.0.1",
diff --git a/superset/assets/spec/javascripts/explore/chartActions_spec.js b/superset/assets/spec/javascripts/explore/chartActions_spec.js
new file mode 100644
index 0000000000000..b2e069ab971a8
--- /dev/null
+++ b/superset/assets/spec/javascripts/explore/chartActions_spec.js
@@ -0,0 +1,36 @@
+import { it, describe } from 'mocha';
+import { expect } from 'chai';
+import sinon from 'sinon';
+import $ from 'jquery';
+import * as exploreUtils from '../../../javascripts/explore/exploreUtils';
+import * as actions from '../../../javascripts/explore/actions/chartActions';
+
+describe('chart actions', () => {
+ let dispatch;
+ let urlStub;
+ let ajaxStub;
+ let request;
+
+ beforeEach(() => {
+ dispatch = sinon.spy();
+ urlStub = sinon.stub(exploreUtils, 'getExploreUrl').callsFake(() => ('mockURL'));
+ ajaxStub = sinon.stub($, 'ajax');
+ });
+
+ afterEach(() => {
+ urlStub.restore();
+ ajaxStub.restore();
+ });
+
+ it('should handle query timeout', () => {
+ ajaxStub.yieldsTo('error', { statusText: 'timeout' });
+ request = actions.runQuery({});
+ request(dispatch, sinon.stub().returns({
+ explore: {
+ controls: [],
+ },
+ }));
+ expect(dispatch.callCount).to.equal(3);
+ expect(dispatch.args[0][0].type).to.equal(actions.CHART_UPDATE_TIMEOUT);
+ });
+});
diff --git a/superset/assets/spec/javascripts/explore/exploreActions_spec.js b/superset/assets/spec/javascripts/explore/exploreActions_spec.js
index 9fa02e4b12484..5d2926de2ef12 100644
--- a/superset/assets/spec/javascripts/explore/exploreActions_spec.js
+++ b/superset/assets/spec/javascripts/explore/exploreActions_spec.js
@@ -4,9 +4,8 @@ import { expect } from 'chai';
import sinon from 'sinon';
import $ from 'jquery';
import * as actions from '../../../javascripts/explore/actions/exploreActions';
-import * as exploreUtils from '../../../javascripts/explore/exploreUtils';
import { defaultState } from '../../../javascripts/explore/stores/store';
-import { exploreReducer } from '../../../javascripts/explore/reducers/exploreReducer';
+import exploreReducer from '../../../javascripts/explore/reducers/exploreReducer';
describe('reducers', () => {
it('sets correct control value given a key and value', () => {
@@ -81,69 +80,4 @@ describe('fetching actions', () => {
expect(dispatch.getCall(4).args[0].type).to.equal(actions.TRIGGER_QUERY);
});
});
-
- describe('fetchDashboards', () => {
- const userID = 1;
- const mockDashboardData = {
- pks: ['value'],
- result: [
- { dashboard_title: 'dashboard title' },
- ],
- };
- const makeRequest = () => {
- request = actions.fetchDashboards(userID);
- request(dispatch);
- };
-
- it('makes the ajax request', () => {
- makeRequest();
- expect(ajaxStub.calledOnce).to.be.true;
- });
-
- it('calls correct url', () => {
- const url = '/dashboardmodelviewasync/api/read?_flt_0_owners=' + userID;
- makeRequest();
- expect(ajaxStub.getCall(0).args[0].url).to.equal(url);
- });
-
- it('calls correct actions on error', () => {
- ajaxStub.yieldsTo('error', { responseJSON: { error: 'error text' } });
- makeRequest();
- expect(dispatch.callCount).to.equal(1);
- expect(dispatch.getCall(0).args[0].type).to.equal(actions.FETCH_DASHBOARDS_FAILED);
- });
-
- it('calls correct actions on success', () => {
- ajaxStub.yieldsTo('success', mockDashboardData);
- makeRequest();
- expect(dispatch.callCount).to.equal(1);
- expect(dispatch.getCall(0).args[0].type).to.equal(actions.FETCH_DASHBOARDS_SUCCEEDED);
- });
- });
-});
-
-describe('runQuery', () => {
- let dispatch;
- let urlStub;
- let ajaxStub;
- let request;
-
- beforeEach(() => {
- dispatch = sinon.spy();
- urlStub = sinon.stub(exploreUtils, 'getExploreUrl').callsFake(() => ('mockURL'));
- ajaxStub = sinon.stub($, 'ajax');
- });
-
- afterEach(() => {
- urlStub.restore();
- ajaxStub.restore();
- });
-
- it('should handle query timeout', () => {
- ajaxStub.yieldsTo('error', { statusText: 'timeout' });
- request = actions.runQuery({});
- request(dispatch);
- expect(dispatch.callCount).to.equal(2);
- expect(dispatch.args[0][0].type).to.equal(actions.CHART_UPDATE_TIMEOUT);
- });
});
diff --git a/superset/assets/stylesheets/superset.css b/superset/assets/stylesheets/superset.less
similarity index 91%
rename from superset/assets/stylesheets/superset.css
rename to superset/assets/stylesheets/superset.less
index 5be9a5fd48835..29b14e8a791f3 100644
--- a/superset/assets/stylesheets/superset.css
+++ b/superset/assets/stylesheets/superset.less
@@ -237,6 +237,24 @@ div.widget .slice_container {
.Select-menu-outer {
z-index: 10 !important;
}
+/** not found record **/
+.panel b {
+ display: inline-block;
+ width: 98%;
+ padding: 2rem;
+ margin: 0 1% 20px 1%;
+ background: #f8f8f8;
+}
+
+/** table on both sides of the gap **/
+.panel .table-responsive{
+ margin: 0 1%;
+}
+@media screen and (max-width: 767px) {
+ .panel .table-responsive{
+ width: 98%;
+ }
+}
.list-container {
position: relative;
@@ -305,9 +323,9 @@ div.widget .slice_container {
}
.list-add-action .btn.btn-sm {
- padding: 5px 6px;
- font-size: 10px;
- line-height: 2px;
- border-radius: 50%;
- box-shadow: 2px 2px 4px -1px rgba(0, 0, 0, 1);
+ padding: 5px 6px;
+ font-size: 10px;
+ line-height: 2px;
+ border-radius: 50%;
+ box-shadow: 2px 2px 4px -1px rgba(0, 0, 0, 1);
}
\ No newline at end of file
diff --git a/superset/assets/webpack.config.js b/superset/assets/webpack.config.js
index e3413e5d14c2a..10e41c96bd8ff 100644
--- a/superset/assets/webpack.config.js
+++ b/superset/assets/webpack.config.js
@@ -2,6 +2,7 @@ const webpack = require('webpack');
const path = require('path');
const ManifestPlugin = require('webpack-manifest-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
+const ExtractTextPlugin = require('extract-text-webpack-plugin');
// input dir
const APP_DIR = path.resolve(__dirname, './');
@@ -14,7 +15,7 @@ const config = {
fs: 'empty',
},
entry: {
- 'css-theme': APP_DIR + '/javascripts/css-theme.js',
+ theme: APP_DIR + '/javascripts/theme.js',
common: APP_DIR + '/javascripts/common.js',
addSlice: ['babel-polyfill', APP_DIR + '/javascripts/addSlice/index.jsx'],
dashboard: ['babel-polyfill', APP_DIR + '/javascripts/dashboard/Dashboard.jsx'],
@@ -64,11 +65,24 @@ const config = {
include: APP_DIR + '/node_modules/mapbox-gl/js',
loader: 'babel-loader',
},
- /* for require('*.css') */
+ // Extract css files
{
test: /\.css$/,
include: APP_DIR,
- loader: 'style-loader!css-loader',
+ loader: ExtractTextPlugin.extract({
+ use: ['css-loader'],
+ fallback: 'style-loader',
+ }),
+ },
+ // Optionally extract less files
+ // or any other compile-to-css language
+ {
+ test: /\.less$/,
+ include: APP_DIR,
+ loader: ExtractTextPlugin.extract({
+ use: ['css-loader', 'less-loader'],
+ fallback: 'style-loader',
+ }),
},
/* for css linking images */
{
@@ -92,12 +106,6 @@ const config = {
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
- /* for require('*.less') */
- {
- test: /\.less$/,
- include: APP_DIR,
- loader: 'style-loader!css-loader!less-loader',
- },
/* for mapbox */
{
test: /\.json$/,
@@ -123,6 +131,7 @@ const config = {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
+ new ExtractTextPlugin('[name].[chunkhash].css'),
],
};
if (process.env.NODE_ENV === 'production') {
diff --git a/superset/cli.py b/superset/cli.py
index f6163bb140b09..e4165e6716be7 100755
--- a/superset/cli.py
+++ b/superset/cli.py
@@ -194,7 +194,7 @@ def worker(workers):
celery_app.conf.update(
CELERYD_CONCURRENCY=config.get("SUPERSET_CELERY_WORKERS"))
- worker = celery_worker.worker(app=celery_app)
+ worker = celery_app.Worker(optimization='fair')
worker.run()
diff --git a/superset/config.py b/superset/config.py
index bc91edd07b097..94d8dfc56a673 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -245,6 +245,8 @@ class CeleryConfig(object):
CELERY_RESULT_BACKEND = 'db+sqlite:///celery_results.sqlite'
CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
CELERYD_LOG_LEVEL = 'DEBUG'
+ CELERYD_PREFETCH_MULTIPLIER = 1
+ CELERY_ACKS_LATE = True
CELERY_CONFIG = CeleryConfig
"""
CELERY_CONFIG = None
diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py
index 335f9d26b1fba..6340331ba785a 100644
--- a/superset/connectors/druid/models.py
+++ b/superset/connectors/druid/models.py
@@ -69,11 +69,11 @@ class DruidCluster(Model, AuditMixinNullable):
# short unique name, used in permissions
cluster_name = Column(String(250), unique=True)
coordinator_host = Column(String(255))
- coordinator_port = Column(Integer)
+ coordinator_port = Column(Integer, default=8081)
coordinator_endpoint = Column(
String(255), default='druid/coordinator/v1/metadata')
broker_host = Column(String(255))
- broker_port = Column(Integer)
+ broker_port = Column(Integer, default=8082)
broker_endpoint = Column(String(255), default='druid/v2')
metadata_last_refreshed = Column(DateTime)
cache_timeout = Column(Integer)
diff --git a/superset/migrations/versions/65903709c321_allow_dml.py b/superset/migrations/versions/65903709c321_allow_dml.py
index d14c6a98235cd..9860c503a9ba3 100644
--- a/superset/migrations/versions/65903709c321_allow_dml.py
+++ b/superset/migrations/versions/65903709c321_allow_dml.py
@@ -6,6 +6,8 @@
"""
+import logging
+
# revision identifiers, used by Alembic.
revision = '65903709c321'
down_revision = '4500485bde7d'
diff --git a/superset/templates/appbuilder/navbar.html b/superset/templates/appbuilder/navbar.html
index b5c3d0a074beb..0ea2daec5fb15 100644
--- a/superset/templates/appbuilder/navbar.html
+++ b/superset/templates/appbuilder/navbar.html
@@ -34,12 +34,12 @@
-
+
-
+
diff --git a/superset/templates/superset/base.html b/superset/templates/superset/base.html
index 1a9c42cd89ca3..b47104957a80d 100644
--- a/superset/templates/superset/base.html
+++ b/superset/templates/superset/base.html
@@ -1,21 +1,12 @@
{% extends "appbuilder/baselayout.html" %}
{% block head_css %}
-
-
{{super()}}
- {% endblock %}
-
- {% block head_js %}
- {{super()}}
- {% with filename="css-theme" %}
- {% include "superset/partials/_script_tag.html" %}
- {% endwith %}
+
+
{% endblock %}
{% block tail_js %}
{{super()}}
- {% with filename="common" %}
- {% include "superset/partials/_script_tag.html" %}
- {% endwith %}
+
{% endblock %}
diff --git a/superset/templates/superset/basic.html b/superset/templates/superset/basic.html
index e146c51758b00..87b058d13eff5 100644
--- a/superset/templates/superset/basic.html
+++ b/superset/templates/superset/basic.html
@@ -12,15 +12,16 @@
{% block head_meta %}{% endblock %}
{% block head_css %}
-
-
-
+
+
+
+ {% if entry %}
+
+ {% endif %}
{% endblock %}
{% block head_js %}
- {% with filename="css-theme" %}
- {% include "superset/partials/_script_tag.html" %}
- {% endwith %}
+
{% endblock %}
{% block tail_js %}
+ {% if entry %}
+
+ {% endif %}
{% endblock %}