From 47d25d0f2bbc61716d0c4a2599a8c4a1c5f07c72 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Tue, 4 Apr 2017 20:21:59 -0700 Subject: [PATCH] URL Params macro --- docs/index.rst | 3 + docs/sqllab.rst | 2 + superset/assets/docs | 1 + superset/assets/images/s.png | Bin 0 -> 11833 bytes superset/assets/javascripts/SqlLab/actions.js | 2 +- .../SqlLab/components/VisualizeModal.jsx | 32 ++++++++-- .../javascripts/explorev2/exploreUtils.js | 51 ++++++++++----- .../spec/javascripts/explorev2/utils_spec.jsx | 59 ++++++++++++++++++ superset/jinja_context.py | 17 ++++- superset/sql_parse.py | 5 +- superset/views/core.py | 14 +---- 11 files changed, 151 insertions(+), 35 deletions(-) create mode 120000 superset/assets/docs create mode 100644 superset/assets/images/s.png create mode 100644 superset/assets/spec/javascripts/explorev2/utils_spec.jsx diff --git a/docs/index.rst b/docs/index.rst index a2b65b1d9d440..1956dd1ccc9bf 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,9 +1,12 @@ +.. image:: _static/img/s.png + Superset's documentation '''''''''''''''''''''''' Superset is a data exploration platform designed to be visual, intuitive and interactive. + ---------------- .. warning:: This project was originally named Panoramix, was renamed to diff --git a/docs/sqllab.rst b/docs/sqllab.rst index 50dc5c78632e9..1a8923c1fc644 100644 --- a/docs/sqllab.rst +++ b/docs/sqllab.rst @@ -58,3 +58,5 @@ Superset's Jinja context: .. autoclass:: superset.jinja_context.PrestoTemplateProcessor :members: + +.. autofunction:: superset.jinja_context.url_param diff --git a/superset/assets/docs b/superset/assets/docs new file mode 120000 index 0000000000000..932170420302a --- /dev/null +++ b/superset/assets/docs @@ -0,0 +1 @@ +../../docs/_build/html/ \ No newline at end of file diff --git a/superset/assets/images/s.png b/superset/assets/images/s.png new file mode 100644 index 0000000000000000000000000000000000000000..2031b86a9f5225e90459013bf6f21eebc158f0e0 GIT binary patch literal 11833 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 literal 0 HcmV?d00001 diff --git a/superset/assets/javascripts/SqlLab/actions.js b/superset/assets/javascripts/SqlLab/actions.js index ca12ac8be0c31..721de87923c7c 100644 --- a/superset/assets/javascripts/SqlLab/actions.js +++ b/superset/assets/javascripts/SqlLab/actions.js @@ -113,7 +113,6 @@ export function fetchQueryResults(query) { export function runQuery(query) { return function (dispatch) { dispatch(startQuery(query)); - const sqlJsonUrl = '/superset/sql_json/'; const sqlJsonRequest = { client_id: query.id, database_id: query.dbId, @@ -126,6 +125,7 @@ export function runQuery(query) { tmp_table_name: query.tempTableName, select_as_cta: query.ctas, }; + const sqlJsonUrl = '/superset/sql_json/' + location.search; $.ajax({ type: 'POST', dataType: 'json', diff --git a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx index e612c9f97e97e..3e97b3e3ee5d9 100644 --- a/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx +++ b/superset/assets/javascripts/SqlLab/components/VisualizeModal.jsx @@ -1,3 +1,4 @@ +/* global notify */ import React from 'react'; import { Alert, Button, Col, Modal } from 'react-bootstrap'; @@ -5,6 +6,7 @@ import Select from 'react-select'; import { Table } from 'reactable'; import shortid from 'shortid'; import $ from 'jquery'; +import { getExploreUrl } from '../../explorev2/exploreUtils'; const CHART_TYPES = [ { value: 'dist_bar', label: 'Distribution - Bar Chart', requiresTime: false }, @@ -89,7 +91,9 @@ class VisualizeModal extends React.PureComponent { } } if (!hasTime) { - hints.push('To use this chart type you need at least one column flagged as a date'); + hints.push( + 'To use this chart type you need at least one column ' + + 'flagged as a date'); } } this.setState({ hints }); @@ -113,9 +117,10 @@ class VisualizeModal extends React.PureComponent { chartType: this.state.chartType.value, datasourceName: this.state.datasourceName, columns: this.state.columns, - sql: this.props.query.executedSql, + sql: this.props.query.sql, dbId: this.props.query.dbId, }; + notify.info('Creating a data source and popping a new tab'); $.ajax({ type: 'POST', url: '/superset/sqllab_viz/', @@ -123,9 +128,28 @@ class VisualizeModal extends React.PureComponent { data: { data: JSON.stringify(vizOptions), }, - success: (url) => { - window.open(url); + dataType: 'json', + success: resp => { + const columns = Object.keys(this.state.columns).map(k => this.state.columns[k]); + const data = JSON.parse(resp); + const mainMetric = columns.filter(d => d.agg)[0]; + const mainGroupBy = columns.filter(d => d.is_dim)[0]; + const formData = { + datasource: `${data.table_id}__table`, + viz_type: this.state.chartType.value, + since: '100 years ago', + limit: '0', + }; + if (mainMetric) { + formData.metrics = [mainMetric.name]; + formData.metric = mainMetric.name; + } + if (mainGroupBy) { + formData.groupby = mainGroupBy.name; + } + window.open(getExploreUrl(formData)); }, + error: () => notify('An error occurred while creating the data source'), }); } changeDatasourceName(event) { diff --git a/superset/assets/javascripts/explorev2/exploreUtils.js b/superset/assets/javascripts/explorev2/exploreUtils.js index 59d83d2f14431..5951ff61a2e6c 100644 --- a/superset/assets/javascripts/explorev2/exploreUtils.js +++ b/superset/assets/javascripts/explorev2/exploreUtils.js @@ -1,26 +1,43 @@ /* eslint camelcase: 0 */ -export function getExploreUrl(form_data, endpoint = 'base', force = false) { +import URI from 'urijs'; + +export function getExploreUrl(form_data, endpointType = 'base', force = false, curUrl = null) { if (!form_data.datasource) { return null; } + + + // The search params from the window.location are carried through, + // but can be specified with curUrl (used for unit tests to spoof + // the window.location). + let uri = URI(window.location.search); + if (curUrl) { + uri = URI(URI(curUrl).search()); + } + + // Building the directory part of the URI + let directory = '/superset/explore/'; + if (['json', 'csv', 'query'].indexOf(endpointType) >= 0) { + directory = '/superset/explore_json/'; + } const [datasource_id, datasource_type] = form_data.datasource.split('__'); - let params = `${datasource_type}/${datasource_id}/`; - params += '?form_data=' + encodeURIComponent(JSON.stringify(form_data)); + directory += `${datasource_type}/${datasource_id}/`; + + // Building the querystring (search) part of the URI + const search = uri.search(true); + search.form_data = JSON.stringify(form_data); if (force) { - params += '&force=true'; + search.force = 'true'; + } + if (endpointType === 'csv') { + search.csv = 'true'; + } + if (endpointType === 'standalone') { + search.standalone = 'true'; } - switch (endpoint) { - case 'base': - return `/superset/explore/${params}`; - case 'json': - return `/superset/explore_json/${params}`; - case 'csv': - return `/superset/explore_json/${params}&csv=true`; - case 'standalone': - return `/superset/explore/${params}&standalone=true`; - case 'query': - return `/superset/explore_json/${params}&query=true`; - default: - return `/superset/explore/${params}`; + if (endpointType === 'query') { + search.query = 'true'; } + uri = uri.search(search).directory(directory); + return uri.toString(); } diff --git a/superset/assets/spec/javascripts/explorev2/utils_spec.jsx b/superset/assets/spec/javascripts/explorev2/utils_spec.jsx new file mode 100644 index 0000000000000..111dccc951d9a --- /dev/null +++ b/superset/assets/spec/javascripts/explorev2/utils_spec.jsx @@ -0,0 +1,59 @@ +import { it, describe } from 'mocha'; +import { expect } from 'chai'; +import URI from 'urijs'; +import { getExploreUrl } from '../../../javascripts/explorev2/exploreUtils.js'; + +describe('utils', () => { + const formData = { + datasource: '1__table', + }; + const sFormData = JSON.stringify(formData); + function compareURI(uri1, uri2) { + expect(uri1.toString()).to.equal(uri2.toString()); + } + + it('getExploreUrl generates proper base url', () => { + // This assertion is to show clearly the value of location.href + // in the context of unit tests. + expect(location.href).to.equal('about:blank'); + + compareURI( + URI(getExploreUrl(formData, 'base', false, 'http://superset.com')), + URI('/superset/explore/table/1/').search({ form_data: sFormData }) + ); + }); + it('getExploreUrl generates proper json url', () => { + compareURI( + URI(getExploreUrl(formData, 'json', false, 'superset.com')), + URI('/superset/explore_json/table/1/').search({ form_data: sFormData }) + ); + }); + it('getExploreUrl generates proper json forced url', () => { + compareURI( + URI(getExploreUrl(formData, 'json', true, 'superset.com')), + URI('/superset/explore_json/table/1/') + .search({ form_data: sFormData, force: 'true' }) + ); + }); + it('getExploreUrl generates proper csv URL', () => { + compareURI( + URI(getExploreUrl(formData, 'csv', false, 'superset.com')), + URI('/superset/explore_json/table/1/') + .search({ form_data: sFormData, csv: 'true' }) + ); + }); + it('getExploreUrl generates proper standalone URL', () => { + compareURI( + URI(getExploreUrl(formData, 'standalone', false, 'superset.com')), + URI('/superset/explore/table/1/') + .search({ form_data: sFormData, standalone: 'true' }) + ); + }); + it('getExploreUrl preserves main URLs params', () => { + compareURI( + URI(getExploreUrl(formData, 'json', false, 'superset.com?foo=bar')), + URI('/superset/explore_json/table/1/') + .search({ foo: 'bar', form_data: sFormData }) + ); + }); +}); diff --git a/superset/jinja_context.py b/superset/jinja_context.py index b35915bba6dea..ff1cb67b23e47 100644 --- a/superset/jinja_context.py +++ b/superset/jinja_context.py @@ -6,6 +6,7 @@ import inspect from jinja2.sandbox import SandboxedEnvironment +from flask import request from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta @@ -27,6 +28,18 @@ BASE_CONTEXT.update(config.get('JINJA_CONTEXT_ADDONS', {})) +def url_param(param, default=None): + """Get a url paramater + + :param param: the url parameter to lookup + :type param: str + :param default: the value to return in the absence of the parameter + :type default: str + """ + print(request.args) + return request.args.get(param, default) + + class BaseTemplateProcessor(object): """Base class for database-specific jinja context @@ -52,7 +65,9 @@ def __init__(self, database=None, query=None, table=None, **kwargs): self.schema = query.schema elif table: self.schema = table.schema - self.context = {} + self.context = { + 'url_param': url_param, + } self.context.update(kwargs) self.context.update(BASE_CONTEXT) if self.engine: diff --git a/superset/sql_parse.py b/superset/sql_parse.py index 61966c2a7829d..0faae28b9428a 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -1,6 +1,8 @@ +import logging + import sqlparse from sqlparse.sql import IdentifierList, Identifier -from sqlparse.tokens import DML, Keyword, Name +from sqlparse.tokens import Keyword, Name RESULT_OPERATIONS = {'UNION', 'INTERSECT', 'EXCEPT'} PRECEDES_TABLE_NAME = {'FROM', 'JOIN', 'DESC', 'DESCRIBE', 'WITH'} @@ -13,6 +15,7 @@ def __init__(self, sql_statement): self._table_names = set() self._alias_names = set() # TODO: multistatement support + logging.info("Parsing with sqlparse statement {}".format(self.sql)) self._parsed = sqlparse.parse(self.sql) for statement in self._parsed: self.__extract_from_token(statement) diff --git a/superset/views/core.py b/superset/views/core.py index 5f917c82c3f57..291cf5fb06aa8 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -1710,7 +1710,6 @@ def sqllab_viz(self): SqlaTable = ConnectorRegistry.sources['table'] data = json.loads(request.form.get('data')) table_name = data.get('datasourceName') - viz_type = data.get('chartType') SqlaTable = ConnectorRegistry.sources['table'] table = ( db.session.query(SqlaTable) @@ -1762,16 +1761,9 @@ def sqllab_viz(self): table.columns = cols table.metrics = metrics db.session.commit() - params = { - 'viz_type': viz_type, - 'groupby': dims[0].column_name if dims else None, - 'metrics': metrics[0].metric_name if metrics else None, - 'metric': metrics[0].metric_name if metrics else None, - 'since': '100 years ago', - 'limit': '0', - } - params = "&".join([k + '=' + v for k, v in params.items() if v]) - return '/superset/explore/table/{table.id}/?{params}'.format(**locals()) + return self.json_response(json.dumps({ + 'table_id': table.id, + })) @has_access @expose("/table////")