Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[filter_box] fix time filter and inverted instantFilter #2402

Merged
merged 2 commits into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions superset/assets/javascripts/modules/superset.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,36 +63,18 @@ const px = function () {
const container = $(selector);
const sliceId = data.slice_id;
const formData = applyDefaultFormData(data.form_data);
const jsonEndpoint = getExploreUrl(formData, 'json');
const origJsonEndpoint = jsonEndpoint;
let dttm = 0;
const stopwatch = function () {
dttm += 10;
const num = dttm / 1000;
$('#timer').text(num.toFixed(2) + ' sec');
};
let qrystr = '';
slice = {
data,
formData,
container,
containerId,
selector,
querystring() {
const parser = document.createElement('a');
parser.href = jsonEndpoint;
if (controller.type === 'dashboard') {
parser.href = origJsonEndpoint;
let flts = controller.effectiveExtraFilters(sliceId);
flts = encodeURIComponent(JSON.stringify(flts));
qrystr = parser.search + '&extra_filters=' + flts;
} else if ($('#query').length === 0) {
qrystr = parser.search;
} else {
qrystr = '?' + $('#query').serialize();
}
return qrystr;
},
getWidgetHeader() {
return this.container.parents('div.widget').find('.chart-header');
},
Expand All @@ -104,16 +86,20 @@ const px = function () {
return Mustache.render(s, context);
},
jsonEndpoint() {
const parser = document.createElement('a');
parser.href = jsonEndpoint;
let endpoint = parser.pathname + this.querystring();
return this.endpoint('json');
},
endpoint(endpointType = 'json') {
const formDataExtra = Object.assign({}, formData);
const flts = controller.effectiveExtraFilters(sliceId);
if (flts) {
formDataExtra.extra_filters = flts;
}
let endpoint = getExploreUrl(formDataExtra, endpointType, this.force);
if (endpoint.charAt(0) !== '/') {
// Known issue for IE <= 11:
// https://connect.microsoft.com/IE/feedbackdetail/view/1002846/pathname-incorrect-for-out-of-document-elements
endpoint = '/' + endpoint;
}
endpoint += '&json=true';
endpoint += '&force=' + this.force;
return endpoint;
},
d3format(col, number) {
Expand Down
6 changes: 3 additions & 3 deletions superset/assets/visualizations/filter_box.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class FilterBox extends React.Component {
const selectedValues = Object.assign({}, this.state.selectedValues);
selectedValues[filter] = vals;
this.setState({ selectedValues, hasChanged: true });
this.props.onChange(filter, vals, false, !this.props.instantFiltering);
this.props.onChange(filter, vals, false, this.props.instantFiltering);
}
render() {
let dateFilter;
Expand All @@ -63,7 +63,7 @@ class FilterBox extends React.Component {
}
const options = choices.map((s) => ({ value: s, label: s }));
return (
<div className="m-b-5">
<div className="m-b-5" key={field}>
{field.replace('__', '')}
<Select.Creatable
options={options}
Expand Down Expand Up @@ -109,7 +109,7 @@ class FilterBox extends React.Component {
<div>
{dateFilter}
{filters}
{this.props.instantFiltering &&
{!this.props.instantFiltering &&
<Button
bsSize="small"
bsStyle="primary"
Expand Down
6 changes: 0 additions & 6 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,12 +913,6 @@ def get_form_data(self):
if request.args.get("viz_type"):
# Converting old URLs
d = cast_form_data(request.args)

extra_filters = request.args.get("extra_filters")
filters = d.get('filters', [])
if extra_filters:
extra_filters = json.loads(extra_filters)
d['filters'] = filters + extra_filters
return d

def get_viz(
Expand Down
22 changes: 15 additions & 7 deletions superset/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,18 @@ def get_df(self, query_obj=None):
return df

def get_extra_filters(self):
extra_filters = self.form_data.get('extra_filters')
if not extra_filters:
return {}
return json.loads(extra_filters)
extra_filters = self.form_data.get('extra_filters', [])
return {f['col']: f['val'] for f in extra_filters}

def query_obj(self):
"""Building a query object"""
form_data = self.form_data
groupby = form_data.get("groupby") or []
metrics = form_data.get("metrics") or ['count']

# extra_filters are temporary/contextual filters that are external
# to the slice definition. We use those for dynamic interactive
# filters like the ones emitted by the "Filter Box" visualization
extra_filters = self.get_extra_filters()
granularity = (
form_data.get("granularity") or form_data.get("granularity_sqla")
Expand All @@ -154,13 +156,20 @@ def query_obj(self):
timeseries_limit_metric = form_data.get("timeseries_limit_metric")
row_limit = int(
form_data.get("row_limit") or config.get("ROW_LIMIT"))

# __form and __to are special extra_filters that target time
# boundaries. The rest of extra_filters are simple
# [column_name in list_of_values]. `__` prefix is there to avoid
# potential conflicts with column that would be named `from` or `to`
since = (
extra_filters.get('__from') or form_data.get("since", "1 year ago")
)

from_dttm = utils.parse_human_datetime(since)
now = datetime.now()
if from_dttm > now:
from_dttm = now - (from_dttm - now)

until = extra_filters.get('__to') or form_data.get("until", "now")
to_dttm = utils.parse_human_datetime(until)
if from_dttm > to_dttm:
Expand All @@ -179,15 +188,14 @@ def query_obj(self):
filters = form_data['filters'] if 'filters' in form_data \
else []
for col, vals in self.get_extra_filters().items():
if not (col and vals):
if not (col and vals) or col.startswith('__'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add a comment about __ convention?

continue
elif col in self.datasource.filterable_column_names:
# Quote values with comma to avoid conflict
vals = ["'{}'".format(x) if "," in x else x for x in vals]
filters += [{
'col': col,
'op': 'in',
'val': ",".join(vals),
'val': vals,
}]
d = {
'granularity': granularity,
Expand Down