[add] Save filters to dashboard (#3183)

* [add] Save filters to dashboard

* format code

* fix CI error

* add semicolon  semi

* fix none object

* add test data
optimize the js code
fix the compatibility issue

* fix urllib to urllib.parse

* add space

* update test case

* remove  'return'

* fix error

* update test case
This commit is contained in:
Rogan 2017-08-11 11:49:49 +08:00 committed by Maxime Beauchemin
parent b68084b9ac
commit a5320a0f37
6 changed files with 85 additions and 14 deletions

View File

@ -166,6 +166,10 @@ export function dashboardContainer(dashboard, datasources, userid) {
}
},
effectiveExtraFilters(sliceId) {
// Don't filter the filter_box itself by preselect_filters
if (this.getSlice(sliceId).formData.viz_type === 'filter_box') {
return [];
}
const f = [];
const immuneSlices = this.metadata.filter_immune_slices || [];
if (sliceId && immuneSlices.includes(sliceId)) {
@ -195,21 +199,24 @@ export function dashboardContainer(dashboard, datasources, userid) {
return f;
},
addFilter(sliceId, col, vals, merge = true, refresh = true) {
if (!(sliceId in this.filters)) {
this.filters[sliceId] = {};
}
if (!(col in this.filters[sliceId]) || !merge) {
this.filters[sliceId][col] = vals;
if (this.getSlice(sliceId) && (col === '__from' || col === '__to' ||
this.getSlice(sliceId).formData.groupby.indexOf(col) !== -1)) {
if (!(sliceId in this.filters)) {
this.filters[sliceId] = {};
}
if (!(col in this.filters[sliceId]) || !merge) {
this.filters[sliceId][col] = vals;
// d3.merge pass in array of arrays while some value form filter components
// from and to filter box require string to be process and return
} else if (this.filters[sliceId][col] instanceof Array) {
this.filters[sliceId][col] = d3.merge([this.filters[sliceId][col], vals]);
} else {
this.filters[sliceId][col] = d3.merge([[this.filters[sliceId][col]], vals])[0] || '';
}
if (refresh) {
this.refreshExcept(sliceId);
// d3.merge pass in array of arrays while some value form filter components
// from and to filter box require string to be process and return
} else if (this.filters[sliceId][col] instanceof Array) {
this.filters[sliceId][col] = d3.merge([this.filters[sliceId][col], vals]);
} else {
this.filters[sliceId][col] = d3.merge([[this.filters[sliceId][col]], vals])[0] || '';
}
if (refresh) {
this.refreshExcept(sliceId);
}
}
this.updateFilterParamsInUrl();
},

View File

@ -80,6 +80,7 @@ class SaveModal extends React.PureComponent {
css: this.state.css,
expanded_slices: expandedSlices,
dashboard_title: dashboard.dashboard_title,
default_filters: dashboard.readFilters(),
};
let url = null;
if (saveType === 'overwrite') {

View File

@ -74,6 +74,24 @@ class FilterBox extends React.Component {
);
});
}
// Add created options to filtersChoices, even though it doesn't exist,
// or these options will exist in query sql but invisible to end user.
if (this.state.selectedValues.hasOwnProperty()) {
for (const filterKey of this.state.selectedValues) {
const existValues = this.props.filtersChoices[filterKey].map(f => f.id);
for (const v of this.state.selectedValues[filterKey]) {
if (existValues.indexOf(v) === -1) {
const addChoice = {
filter: filterKey,
id: v,
text: v,
metric: 0,
};
this.props.filtersChoices[filterKey].push(addChoice);
}
}
}
}
const filters = Object.keys(this.props.filtersChoices).map((filter) => {
const data = this.props.filtersChoices[filter];
const maxes = {};

View File

@ -322,6 +322,14 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin):
@property
def url(self):
if self.json_metadata:
# add default_filters to the preselect_filters of dashboard
json_metadata = json.loads(self.json_metadata)
default_filters = json_metadata.get('default_filters')
if default_filters:
filters = parse.quote(default_filters.encode('utf8'))
return "/superset/dashboard/{}/?preselect_filters={}".format(
self.slug or self.id, filters)
return "/superset/dashboard/{}/".format(self.slug or self.id)
@property

View File

@ -1352,6 +1352,7 @@ class Superset(BaseSupersetView):
if 'filter_immune_slice_fields' not in md:
md['filter_immune_slice_fields'] = {}
md['expanded_slices'] = data['expanded_slices']
md['default_filters'] = data.get('default_filters', '')
dashboard.json_metadata = json.dumps(md, indent=4)
@api

View File

@ -380,6 +380,42 @@ class CoreTests(SupersetTestCase):
resp = self.get_resp(url, data=dict(data=json.dumps(data)))
self.assertIn("SUCCESS", resp)
def test_save_dash_with_filter(self, username='admin'):
self.login(username=username)
dash = db.session.query(models.Dashboard).filter_by(
slug="world_health").first()
positions = []
for i, slc in enumerate(dash.slices):
d = {
'col': 0,
'row': i * 4,
'size_x': 4,
'size_y': 4,
'slice_id': '{}'.format(slc.id)}
positions.append(d)
filters = {str(dash.slices[0].id): {'region': ['North America']}}
default_filters = json.dumps(filters)
data = {
'css': '',
'expanded_slices': {},
'positions': positions,
'dashboard_title': dash.dashboard_title,
'default_filters': default_filters
}
url = '/superset/save_dash/{}/'.format(dash.id)
resp = self.get_resp(url, data=dict(data=json.dumps(data)))
self.assertIn("SUCCESS", resp)
updatedDash = db.session.query(models.Dashboard).filter_by(
slug="world_health").first()
new_url = updatedDash.url
self.assertIn("region", new_url)
resp = self.get_resp(new_url)
self.assertIn("North America", resp)
def test_save_dash_with_dashboard_title(self, username='admin'):
self.login(username=username)
dash = (