diff --git a/superset-frontend/spec/javascripts/explore/AdhocFilter_spec.js b/superset-frontend/spec/javascripts/explore/AdhocFilter_spec.js index a559bd7099018..dd4818128e363 100644 --- a/superset-frontend/spec/javascripts/explore/AdhocFilter_spec.js +++ b/superset-frontend/spec/javascripts/explore/AdhocFilter_spec.js @@ -40,6 +40,7 @@ describe('AdhocFilter', () => { filterOptionName: adhocFilter.filterOptionName, sqlExpression: null, fromFormData: false, + isExtra: false, }); }); diff --git a/superset-frontend/src/explore/AdhocFilter.js b/superset-frontend/src/explore/AdhocFilter.js index c11d4fdef1d27..7520cec9bcd53 100644 --- a/superset-frontend/src/explore/AdhocFilter.js +++ b/superset-frontend/src/explore/AdhocFilter.js @@ -79,6 +79,7 @@ export default class AdhocFilter { this.operator = null; this.comparator = null; } + this.isExtra = !!adhocFilter.isExtra; this.fromFormData = !!adhocFilter.filterOptionName; this.filterOptionName = diff --git a/superset-frontend/src/explore/components/AdhocFilterOption.jsx b/superset-frontend/src/explore/components/AdhocFilterOption.jsx index 0c9ce81c1c20a..10979c24ffad1 100644 --- a/superset-frontend/src/explore/components/AdhocFilterOption.jsx +++ b/superset-frontend/src/explore/components/AdhocFilterOption.jsx @@ -19,11 +19,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Label, OverlayTrigger } from 'react-bootstrap'; +import { t } from '@superset-ui/translation'; import AdhocFilterEditPopover from './AdhocFilterEditPopover'; import AdhocFilter from '../AdhocFilter'; import columnType from '../propTypes/columnType'; import adhocMetricType from '../propTypes/adhocMetricType'; +import InfoTooltipWithTrigger from '../../components/InfoTooltipWithTrigger'; const propTypes = { adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired, @@ -80,7 +82,6 @@ export default class AdhocFilterOption extends React.PureComponent { datasource={this.props.datasource} /> ); - return ( - +
+ {adhocFilter.isExtra && ( + + )} + +
); } diff --git a/superset/examples/random_time_series.py b/superset/examples/random_time_series.py index 151d04c7f4a23..7ce865cbd33fd 100644 --- a/superset/examples/random_time_series.py +++ b/superset/examples/random_time_series.py @@ -60,8 +60,8 @@ def load_random_time_series_data(only_metadata=False, force=False): slice_data = { "granularity_sqla": "day", "row_limit": config["ROW_LIMIT"], - "since": "1 year ago", - "until": "now", + "since": "2019-01-01", + "until": "2019-02-01", "metric": "count", "viz_type": "cal_heatmap", "domain_granularity": "month", diff --git a/superset/utils/core.py b/superset/utils/core.py index 23d6d4ef9256d..e23b4695911f4 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -805,6 +805,7 @@ def to_adhoc(filt, expressionType="SIMPLE", clause="where"): "clause": clause.upper(), "expressionType": expressionType, "filterOptionName": str(uuid.uuid4()), + "isExtra": True if filt.get("isExtra") is True else False, } if expressionType == "SIMPLE": @@ -860,6 +861,7 @@ def get_filter_key(f): existing_filters[get_filter_key(existing)] = existing["comparator"] for filtr in form_data["extra_filters"]: + filtr["isExtra"] = True # Pull out time filters/options and merge into form data if date_options.get(filtr["col"]): if filtr.get("val"): diff --git a/superset/views/core.py b/superset/views/core.py index 447461ef3f740..eb8efb15d3f9a 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -946,6 +946,12 @@ def filter(self, datasource_type, datasource_id, column): ) return json_success(payload) + @staticmethod + def remove_extra_filters(filters): + """Extra filters are ones inherited from the dashboard's temporary context + Those should not be saved when saving the chart""" + return [f for f in filters if not f.get("isExtra")] + def save_or_overwrite_slice( self, args, @@ -967,6 +973,10 @@ def save_or_overwrite_slice( form_data.pop("slice_id") # don't save old slice_id slc = Slice(owners=[g.user] if g.user else []) + form_data["adhoc_filters"] = self.remove_extra_filters( + form_data.get("adhoc_filters", []) + ) + slc.params = json.dumps(form_data, indent=2, sort_keys=True) slc.datasource_name = datasource_name slc.viz_type = form_data["viz_type"] diff --git a/tests/core_tests.py b/tests/core_tests.py index 8b4ce6978edab..8d5641bb350f7 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -288,9 +288,10 @@ def test_save_slice(self): self.login(username="admin") slice_name = f"Energy Sankey" slice_id = self.get_slice(slice_name, db.session).id - copy_name = f"Test Sankey Save_{random.random()}" + copy_name_prefix = "Test Sankey" + copy_name = f"{copy_name_prefix}[save]{random.random()}" tbl_id = self.table_ids.get("energy_usage") - new_slice_name = f"Test Sankey Overwrite_{random.random()}" + new_slice_name = f"{copy_name_prefix}[overwrite]{random.random()}" url = ( "/superset/explore/table/{}/?slice_name={}&" @@ -298,8 +299,9 @@ def test_save_slice(self): ) form_data = { + "adhoc_filters": [], "viz_type": "sankey", - "groupby": "target", + "groupby": ["target"], "metric": "sum__value", "row_limit": 5000, "slice_id": slice_id, @@ -319,8 +321,9 @@ def test_save_slice(self): self.assertEqual(slc.viz.form_data, form_data) form_data = { + "adhoc_filters": [], "viz_type": "sankey", - "groupby": "source", + "groupby": ["source"], "metric": "sum__value", "row_limit": 5000, "slice_id": new_slice_id, @@ -338,7 +341,13 @@ def test_save_slice(self): self.assertEqual(slc.viz.form_data, form_data) # Cleanup - db.session.delete(slc) + slices = ( + db.session.query(Slice) + .filter(Slice.slice_name.like(copy_name_prefix + "%")) + .all() + ) + for slc in slices: + db.session.delete(slc) db.session.commit() def test_filter_endpoint(self): diff --git a/tests/viz_tests.py b/tests/viz_tests.py index 80da72ec52948..ab10f49706658 100644 --- a/tests/viz_tests.py +++ b/tests/viz_tests.py @@ -1081,6 +1081,7 @@ def test_filter_nulls(self, mock_uuid4): "comparator": "", "operator": "IS NOT NULL", "subject": "lat", + "isExtra": False, }, { "clause": "WHERE", @@ -1089,6 +1090,7 @@ def test_filter_nulls(self, mock_uuid4): "comparator": "", "operator": "IS NOT NULL", "subject": "lon", + "isExtra": False, }, ], "delimited_key": [ @@ -1099,6 +1101,7 @@ def test_filter_nulls(self, mock_uuid4): "comparator": "", "operator": "IS NOT NULL", "subject": "lonlat", + "isExtra": False, } ], "geohash_key": [ @@ -1109,6 +1112,7 @@ def test_filter_nulls(self, mock_uuid4): "comparator": "", "operator": "IS NOT NULL", "subject": "geo", + "isExtra": False, } ], }