diff --git a/superset/assets/javascripts/dashboard/Dashboard.jsx b/superset/assets/javascripts/dashboard/Dashboard.jsx index dc02a7ef14f44..e8509a5f06320 100644 --- a/superset/assets/javascripts/dashboard/Dashboard.jsx +++ b/superset/assets/javascripts/dashboard/Dashboard.jsx @@ -14,8 +14,8 @@ import Header from './components/Header'; require('bootstrap'); require('../../stylesheets/dashboard.css'); -export function getInitialState(dashboardData, context) { - const dashboard = Object.assign({ context }, utils.controllerInterface, dashboardData); +export function getInitialState(boostrapData) { + const dashboard = Object.assign({}, utils.controllerInterface, boostrapData.dashboard_data); dashboard.firstLoad = true; dashboard.posDict = {}; @@ -24,12 +24,8 @@ export function getInitialState(dashboardData, context) { dashboard.posDict[position.slice_id] = position; }); } - dashboard.curUserId = dashboard.context.user_id; dashboard.refreshTimer = null; - - const state = { - dashboard, - }; + const state = Object.assign({}, boostrapData, { dashboard }); return state; } @@ -98,19 +94,19 @@ function initDashboardView(dashboard) { $('[data-toggle="tooltip"]').tooltip({ container: 'body' }); } -export function dashboardContainer(dashboard) { +export function dashboardContainer(dashboard, datasources) { return Object.assign({}, dashboard, { type: 'dashboard', filters: {}, init() { this.sliceObjects = []; - dashboard.slices.forEach((data) => { + dashboard.slices.forEach(data => { if (data.error) { - const html = '
' + data.error + '
'; - $('#slice_' + data.slice_id).find('.token').html(html); + const html = `
${data.error}
`; + $(`#slice_${data.slice_id}`).find('.token').html(html); } else { - const slice = px.Slice(data, this); - $('#slice_' + data.slice_id).find('a.refresh').click(() => { + const slice = px.Slice(data, datasources[data.form_data.datasource], this); + $(`#slice_${data.slice_id}`).find('a.refresh').click(() => { slice.render(true); }); this.sliceObjects.push(slice); @@ -337,11 +333,10 @@ export function dashboardContainer(dashboard) { $(document).ready(() => { // Getting bootstrapped data from the DOM utils.initJQueryAjaxCSRF(); - const dashboardData = $('.dashboard').data('dashboard'); - const contextData = $('.dashboard').data('context'); + const dashboardData = $('.dashboard').data('bootstrap'); - const state = getInitialState(dashboardData, contextData); - const dashboard = dashboardContainer(state.dashboard); + const state = getInitialState(dashboardData); + const dashboard = dashboardContainer(state.dashboard, state.datasources); initDashboardView(dashboard); dashboard.init(); }); diff --git a/superset/assets/javascripts/dashboard/components/Controls.jsx b/superset/assets/javascripts/dashboard/components/Controls.jsx index cb78d862bcd8a..463a75ffb3251 100644 --- a/superset/assets/javascripts/dashboard/components/Controls.jsx +++ b/superset/assets/javascripts/dashboard/components/Controls.jsx @@ -43,7 +43,7 @@ class Controls extends React.PureComponent { } render() { const dashboard = this.props.dashboard; - const canSave = dashboard.context.dash_save_perm; + const canSave = dashboard.dash_save_perm; const emailBody = `Checkout this dashboard: ${window.location.href}`; const emailLink = 'mailto:?Subject=Superset%20Dashboard%20' + `${dashboard.dashboard_title}&Body=${emailBody}`; diff --git a/superset/assets/javascripts/dashboard/components/Header.jsx b/superset/assets/javascripts/dashboard/components/Header.jsx index 58230b95cdebf..3e8e407f86a95 100644 --- a/superset/assets/javascripts/dashboard/components/Header.jsx +++ b/superset/assets/javascripts/dashboard/components/Header.jsx @@ -25,7 +25,7 @@ class Header extends React.PureComponent {
- {!this.props.dashboard.context.standalone_mode && + {!this.props.dashboard.standalone_mode && }
diff --git a/superset/assets/javascripts/modules/superset.js b/superset/assets/javascripts/modules/superset.js index 6076875dec23a..d95d159acbf6a 100644 --- a/superset/assets/javascripts/modules/superset.js +++ b/superset/assets/javascripts/modules/superset.js @@ -55,7 +55,7 @@ const px = function () { }) .tooltip(); } - const Slice = function (data, controller) { + const Slice = function (data, datasource, controller) { let timer; const token = $('#token_' + data.slice_id); const containerId = 'con_' + data.slice_id; @@ -74,6 +74,7 @@ const px = function () { formData, container, containerId, + datasource, selector, getWidgetHeader() { return this.container.parents('div.widget').find('.chart-header'); @@ -105,11 +106,11 @@ const px = function () { d3format(col, number) { // uses the utils memoized d3format function and formats based on // column level defined preferences - if (data.column_formats) { - const format = data.column_formats[col]; - return utils.d3format(format, number); + let format = '.3s'; + if (this.datasource.column_formats[col]) { + format = this.datasource.column_formats[col]; } - return utils.d3format('.3s', number); + return utils.d3format(format, number); }, /* eslint no-shadow: 0 */ always(data) { diff --git a/superset/connectors/base.py b/superset/connectors/base.py index c96f2bbb9969b..02016a09319f8 100644 --- a/superset/connectors/base.py +++ b/superset/connectors/base.py @@ -44,6 +44,11 @@ class BaseDatasource(AuditMixinNullable, ImportMixin): # placeholder for a relationship to a derivative of BaseMetric metrics = [] + @property + def uid(self): + """Unique id across datasource types""" + return "{self.id}__{self.type}".format(**locals()) + @property def column_names(self): return sorted([c.column_name for c in self.columns]) diff --git a/superset/models/core.py b/superset/models/core.py index 79b2e63b8b32b..0cbcd15c4b413 100644 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -336,11 +336,11 @@ def dashboard_link(self): '{title}'.format(**locals())) @property - def json_data(self): + def data(self): positions = self.position_json if positions: positions = json.loads(positions) - d = { + return { 'id': self.id, 'metadata': self.params_dict, 'css': self.css, @@ -349,7 +349,6 @@ def json_data(self): 'slices': [slc.data for slc in self.slices], 'position_json': positions, } - return json.dumps(d) @property def params(self): diff --git a/superset/templates/superset/dashboard.html b/superset/templates/superset/dashboard.html index f899d6fa0a24b..8fe4a6ed5bfc1 100644 --- a/superset/templates/superset/dashboard.html +++ b/superset/templates/superset/dashboard.html @@ -6,13 +6,12 @@ {% include "superset/partials/_script_tag.html" %} {% endwith %} {% endblock %} -{% block title %}[dashboard] {{ dashboard.dashboard_title }}{% endblock %} +{% block title %}[dashboard] {{ dashboard_title }}{% endblock %} {% block body %}
{% include 'superset/flash_wrapper.html' %} diff --git a/superset/views/core.py b/superset/views/core.py index 1d4e4f88a0e5d..1c0b7bb688aba 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -1257,7 +1257,7 @@ def copy_dash(self, dashboard_id): self._set_dash_metadata(dash, data) session.add(dash) session.commit() - dash_json = dash.json_data + dash_json = json.dumps(dash.data) session.close() return json_success(dash_json) @@ -1628,29 +1628,36 @@ def dashboard(self, dashboard_id): "danger") return redirect( 'superset/request_access/?' - 'dashboard_id={dash.id}&' - ''.format(**locals())) + 'dashboard_id={dash.id}&'.format(**locals())) # Hack to log the dashboard_id properly, even when getting a slug @log_this def dashboard(**kwargs): # noqa pass dashboard(dashboard_id=dash.id) + dash_edit_perm = check_ownership(dash, raise_if_false=False) dash_save_perm = \ dash_edit_perm and self.can_access('can_save_dash', 'Superset') - standalone = request.args.get("standalone") == "true" - context = dict( - user_id=g.user.get_id(), - dash_save_perm=dash_save_perm, - dash_edit_perm=dash_edit_perm, - standalone_mode=standalone, - ) + + dashboard_data = dash.data + dashboard_data.update({ + 'standalone_mode': request.args.get("standalone") == "true", + }) + + bootstrap_data = { + 'user_id': g.user.get_id(), + 'dash_save_perm': dash_save_perm, + 'dash_edit_perm': dash_edit_perm, + 'dash_edit_perm': check_ownership(dash, raise_if_false=False), + 'dashboard_data': dash.data, + 'datasources': {ds.uid: ds.data for ds in datasources}, + } + return self.render_template( "superset/dashboard.html", - dashboard=dash, - context=json.dumps(context), - standalone_mode=standalone, + dashboard_title=dash.dashboard_title, + bootstrap_data=json.dumps(bootstrap_data), ) @has_access diff --git a/tests/core_tests.py b/tests/core_tests.py index d18f2d93900c5..f9e6c8a964c4d 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -396,7 +396,7 @@ def test_copy_dash(self, username='admin'): self.client.post(url, data=dict(data=json.dumps(data))) dash = db.session.query(models.Dashboard).filter_by( id=dash_id).first() - orig_json_data = json.loads(dash.json_data) + orig_json_data = dash.data # Verify that copy matches original url = '/superset/copy_dash/{}/'.format(dash_id)