mirror of
https://github.com/apache/superset.git
synced 2026-04-20 00:24:38 +00:00
fix(dashboard): update cross filter scoping chart id references during dashboard import (#34418)
Co-authored-by: chanduapple <80615671+chanduapple@users.noreply.github.com> Co-authored-by: chandrasekhar jandhyam <chandrasekhar.jandhyam@digital.ai> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -139,7 +139,55 @@ def update_id_refs( # pylint: disable=too-many-locals # noqa: C901
|
|||||||
native_filter["scope"]["excluded"] = [
|
native_filter["scope"]["excluded"] = [
|
||||||
id_map[old_id] for old_id in scope_excluded if old_id in id_map
|
id_map[old_id] for old_id in scope_excluded if old_id in id_map
|
||||||
]
|
]
|
||||||
|
fixed = update_cross_filter_scoping(fixed, id_map)
|
||||||
|
return fixed
|
||||||
|
|
||||||
|
|
||||||
|
def update_cross_filter_scoping(
|
||||||
|
config: dict[str, Any], id_map: dict[int, int]
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
# fix cross filter references
|
||||||
|
fixed = config.copy()
|
||||||
|
|
||||||
|
cross_filter_global_config = fixed.get("metadata", {}).get(
|
||||||
|
"global_chart_configuration", {}
|
||||||
|
)
|
||||||
|
scope_excluded = cross_filter_global_config.get("scope", {}).get("excluded", [])
|
||||||
|
if scope_excluded:
|
||||||
|
cross_filter_global_config["scope"]["excluded"] = [
|
||||||
|
id_map[old_id] for old_id in scope_excluded if old_id in id_map
|
||||||
|
]
|
||||||
|
|
||||||
|
if "chart_configuration" in (metadata := fixed.get("metadata", {})):
|
||||||
|
# Build remapped configuration in a single pass for clarity/readability.
|
||||||
|
new_chart_configuration: dict[str, Any] = {}
|
||||||
|
for old_id_str, chart_config in metadata["chart_configuration"].items():
|
||||||
|
try:
|
||||||
|
old_id_int = int(old_id_str)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_id = id_map.get(old_id_int)
|
||||||
|
if new_id is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(chart_config, dict):
|
||||||
|
chart_config["id"] = new_id
|
||||||
|
|
||||||
|
# Update cross filter scope excluded ids
|
||||||
|
scope = chart_config.get("crossFilters", {}).get("scope", {})
|
||||||
|
if isinstance(scope, dict):
|
||||||
|
excluded_scope = scope.get("excluded", [])
|
||||||
|
if excluded_scope:
|
||||||
|
chart_config["crossFilters"]["scope"]["excluded"] = [
|
||||||
|
id_map[old_id]
|
||||||
|
for old_id in excluded_scope
|
||||||
|
if old_id in id_map
|
||||||
|
]
|
||||||
|
|
||||||
|
new_chart_configuration[str(new_id)] = chart_config
|
||||||
|
|
||||||
|
metadata["chart_configuration"] = new_chart_configuration
|
||||||
return fixed
|
return fixed
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -121,3 +121,81 @@ def test_update_native_filter_config_scope_excluded():
|
|||||||
},
|
},
|
||||||
"metadata": {"native_filter_configuration": [{"scope": {"excluded": [1, 2]}}]},
|
"metadata": {"native_filter_configuration": [{"scope": {"excluded": [1, 2]}}]},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_id_refs_cross_filter_chart_configuration_key_and_excluded_mapping():
|
||||||
|
from superset.commands.dashboard.importers.v1.utils import update_id_refs
|
||||||
|
|
||||||
|
# Build a minimal dashboard position with uuids -> old ids
|
||||||
|
config: dict[str, Any] = {
|
||||||
|
"position": {
|
||||||
|
"CHART1": {
|
||||||
|
"id": "CHART1",
|
||||||
|
"meta": {"chartId": 101, "uuid": "uuid1"},
|
||||||
|
"type": "CHART",
|
||||||
|
},
|
||||||
|
"CHART2": {
|
||||||
|
"id": "CHART2",
|
||||||
|
"meta": {"chartId": 102, "uuid": "uuid2"},
|
||||||
|
"type": "CHART",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"chart_configuration": {
|
||||||
|
"101": {
|
||||||
|
"id": 101,
|
||||||
|
"crossFilters": {"scope": {"excluded": [102, 103]}},
|
||||||
|
},
|
||||||
|
"104": {"crossFilters": {"scope": {"excluded": [105]}}},
|
||||||
|
},
|
||||||
|
"global_chart_configuration": {"scope": {"excluded": [102, 999]}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_ids = {"uuid1": 1, "uuid2": 2}
|
||||||
|
dataset_info: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
|
fixed = update_id_refs(config, chart_ids, dataset_info)
|
||||||
|
|
||||||
|
metadata = fixed["metadata"]
|
||||||
|
# Expect top-level key remapped from "101" to "1"
|
||||||
|
assert "1" in metadata["chart_configuration"]
|
||||||
|
assert "101" not in metadata["chart_configuration"]
|
||||||
|
|
||||||
|
chart_config = metadata["chart_configuration"]["1"]
|
||||||
|
# Expect inner id updated to new id
|
||||||
|
assert chart_config.get("id") == 1
|
||||||
|
# Expect excluded list remapped and unknown ids dropped
|
||||||
|
assert chart_config["crossFilters"]["scope"]["excluded"] == [2]
|
||||||
|
|
||||||
|
# Expect entries without id_map mapping to be dropped
|
||||||
|
assert "104" not in metadata["chart_configuration"]
|
||||||
|
|
||||||
|
# Expect global scope excluded remapped too
|
||||||
|
assert metadata["global_chart_configuration"]["scope"]["excluded"] == [2]
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_id_refs_cross_filter_handles_string_excluded():
|
||||||
|
from superset.commands.dashboard.importers.v1.utils import update_id_refs
|
||||||
|
|
||||||
|
config: dict[str, Any] = {
|
||||||
|
"position": {
|
||||||
|
"CHART1": {
|
||||||
|
"id": "CHART1",
|
||||||
|
"meta": {"chartId": 101, "uuid": "uuid1"},
|
||||||
|
"type": "CHART",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"chart_configuration": {
|
||||||
|
"101": {"crossFilters": {"scope": {"excluded": "all"}}}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_ids = {"uuid1": 1}
|
||||||
|
dataset_info: dict[str, dict[str, Any]] = {}
|
||||||
|
|
||||||
|
fixed = update_id_refs(config, chart_ids, dataset_info)
|
||||||
|
# Should not raise and should remap key
|
||||||
|
assert "1" in fixed["metadata"]["chart_configuration"]
|
||||||
|
|||||||
Reference in New Issue
Block a user