mirror of https://github.com/apache/superset.git
URL Params macro (#2537)
This commit is contained in:
parent
b97a8275d4
commit
10773f96a7
|
@ -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
|
||||
|
|
|
@ -58,3 +58,5 @@ Superset's Jinja context:
|
|||
|
||||
.. autoclass:: superset.jinja_context.PrestoTemplateProcessor
|
||||
:members:
|
||||
|
||||
.. autofunction:: superset.jinja_context.url_param
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../docs/_build/html/
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
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 === 'csv') {
|
||||
search.csv = 'true';
|
||||
}
|
||||
if (endpointType === 'standalone') {
|
||||
search.standalone = 'true';
|
||||
}
|
||||
if (endpointType === 'query') {
|
||||
search.query = 'true';
|
||||
}
|
||||
uri = uri.search(search).directory(directory);
|
||||
return uri.toString();
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
);
|
||||
});
|
||||
});
|
|
@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||
|
||||
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 = {
|
|||
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 @@ class BaseTemplateProcessor(object):
|
|||
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:
|
||||
|
|
|
@ -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 @@ class SupersetQuery(object):
|
|||
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)
|
||||
|
|
|
@ -1710,7 +1710,6 @@ class Superset(BaseSupersetView):
|
|||
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 @@ class Superset(BaseSupersetView):
|
|||
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/<database_id>/<table_name>/<schema>/")
|
||||
|
|
Loading…
Reference in New Issue