This is an automated email from the ASF dual-hosted git repository. graceguo pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push: new 421aeb4 [dashboard] fix filter_scopes when copy dashboard with duplicate_slices (#9188) 421aeb4 is described below commit 421aeb4605173bbb162a2aff4855ac49ea1b3e40 Author: Grace Guo <grace....@airbnb.com> AuthorDate: Mon Feb 24 13:45:29 2020 -0800 [dashboard] fix filter_scopes when copy dashboard with duplicate_slices (#9188) * [dashboard] fix filter_scopes when copy dashboard with duplicate_slices * code cleanup --- superset/models/dashboard.py | 21 +++++++++++---------- superset/utils/dashboard_filter_scopes_converter.py | 14 ++++++++++++++ superset/views/core.py | 19 +++++++++++++------ 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py index 60af209..ae9ed5f 100644 --- a/superset/models/dashboard.py +++ b/superset/models/dashboard.py @@ -44,7 +44,10 @@ from superset.models.slice import Slice as Slice from superset.models.tags import DashboardUpdater from superset.models.user_attributes import UserAttribute from superset.utils import core as utils -from superset.utils.dashboard_filter_scopes_converter import convert_filter_scopes +from superset.utils.dashboard_filter_scopes_converter import ( + convert_filter_scopes, + copy_filter_scopes, +) if TYPE_CHECKING: # pylint: disable=unused-import @@ -288,10 +291,10 @@ class Dashboard( # pylint: disable=too-many-instance-attributes # and will remove the existing dashboard - slice association slices = copy(dashboard_to_import.slices) old_json_metadata = json.loads(dashboard_to_import.json_metadata or "{}") - old_to_new_slc_id_dict = {} + old_to_new_slc_id_dict: Dict[int, int] = {} new_timed_refresh_immune_slices = [] new_expanded_slices = {} - new_filter_scopes = {} + new_filter_scopes: Dict[str, Dict] = {} i_params_dict = dashboard_to_import.params_dict remote_id_slice_map = { slc.params_dict["remote_id"]: slc @@ -338,13 +341,11 @@ class Dashboard( # pylint: disable=too-many-instance-attributes filter_scopes = old_json_metadata.get("filter_scopes") # then replace old slice id to new slice id: - for (slice_id, scopes) in filter_scopes.items(): - new_filter_key = old_to_new_slc_id_dict[int(slice_id)] - new_filter_scopes[str(new_filter_key)] = scopes - for scope in scopes.values(): - scope["immune"] = [ - old_to_new_slc_id_dict[slice_id] for slice_id in scope.get("immune") - ] + if filter_scopes: + new_filter_scopes = copy_filter_scopes( + old_to_new_slc_id_dict=old_to_new_slc_id_dict, + old_filter_scopes=filter_scopes, + ) # override the dashboard existing_dashboard = None diff --git a/superset/utils/dashboard_filter_scopes_converter.py b/superset/utils/dashboard_filter_scopes_converter.py index 7fff9dd..6546479 100644 --- a/superset/utils/dashboard_filter_scopes_converter.py +++ b/superset/utils/dashboard_filter_scopes_converter.py @@ -70,3 +70,17 @@ def convert_filter_scopes(json_metadata: Dict, filters: List[Slice]): filter_scopes[filter_id] = filter_fields return filter_scopes + + +def copy_filter_scopes( + old_to_new_slc_id_dict: Dict[int, int], old_filter_scopes: Dict[str, Dict] +) -> Dict: + new_filter_scopes = {} + for (slice_id, scopes) in old_filter_scopes.items(): + new_filter_key = old_to_new_slc_id_dict[int(slice_id)] + new_filter_scopes[str(new_filter_key)] = scopes + for scope in scopes.values(): + scope["immune"] = [ + old_to_new_slc_id_dict[slice_id] for slice_id in scope.get("immune") + ] + return new_filter_scopes diff --git a/superset/views/core.py b/superset/views/core.py index 0a7872e..d876643 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -81,6 +81,7 @@ from superset.models.user_attributes import UserAttribute from superset.sql_parse import ParsedQuery from superset.sql_validators import get_validator_by_name from superset.utils import core as utils, dashboard_import_export +from superset.utils.dashboard_filter_scopes_converter import copy_filter_scopes from superset.utils.dates import now_as_float from superset.utils.decorators import etag_cache, stats_timing from superset.views.database.filters import DatabaseFilter @@ -1177,27 +1178,33 @@ class Superset(BaseSupersetView): if data["duplicate_slices"]: # Duplicating slices as well, mapping old ids to new ones - old_to_new_sliceids = {} + old_to_new_sliceids: Dict[int, int] = {} for slc in original_dash.slices: new_slice = slc.clone() new_slice.owners = [g.user] if g.user else [] session.add(new_slice) session.flush() new_slice.dashboards.append(dash) - old_to_new_sliceids["{}".format(slc.id)] = "{}".format(new_slice.id) + old_to_new_sliceids[slc.id] = new_slice.id # update chartId of layout entities - # in v2_dash positions json data, chartId should be integer, - # while in older version slice_id is string type for value in data["positions"].values(): if ( isinstance(value, dict) and value.get("meta") and value.get("meta").get("chartId") ): - old_id = "{}".format(value.get("meta").get("chartId")) - new_id = int(old_to_new_sliceids[old_id]) + old_id = value.get("meta").get("chartId") + new_id = old_to_new_sliceids[old_id] value["meta"]["chartId"] = new_id + + # replace filter_id and immune ids from old slice id to new slice id: + if "filter_scopes" in data: + new_filter_scopes = copy_filter_scopes( + old_to_new_slc_id_dict=old_to_new_sliceids, + old_filter_scopes=json.loads(data["filter_scopes"] or "{}"), + ) + data["filter_scopes"] = json.dumps(new_filter_scopes) else: dash.slices = original_dash.slices dash.params = original_dash.params