This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 46b2d7d7a9c test(dashboard-import): pin native filter scope rootPath
preservation (#19944) (#40135)
46b2d7d7a9c is described below
commit 46b2d7d7a9cdfe046227c43ac43ebed0b26d2901
Author: Evan Rusackas <[email protected]>
AuthorDate: Wed May 20 12:25:34 2026 -0700
test(dashboard-import): pin native filter scope rootPath preservation
(#19944) (#40135)
Co-authored-by: Claude Code <[email protected]>
---
.../dashboards/commands/importers/v1/utils_test.py | 115 +++++++++++++++++++++
1 file changed, 115 insertions(+)
diff --git a/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py
b/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py
index 88dfa393c6f..6fe39c1cc3d 100644
--- a/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py
+++ b/tests/unit_tests/dashboards/commands/importers/v1/utils_test.py
@@ -123,6 +123,121 @@ def test_update_native_filter_config_scope_excluded():
}
+def test_update_native_filter_config_preserves_rootpath_and_remaps_excluded():
+ """
+ Regression guard for #19944: a native filter's ``scope`` has two parts that
+ must both survive an export/import roundtrip:
+
+ - ``rootPath`` controls *which* dashboard sections (tabs/rows) the filter
+ applies to. It uses position keys (``ROOT_ID``, ``TAB-xxx``), not chart
+ IDs, so ``update_id_refs`` must leave it untouched.
+ - ``excluded`` is a list of chart IDs the filter does NOT apply to within
+ its rootPath. Those IDs must be remapped to destination-env IDs.
+
+ The original bug report — "filters are automatically applied to all charts,
+ even if a different scoping was defined before the export" — describes a
+ rootPath silently being collapsed back to ``["ROOT_ID"]`` (i.e. "apply
+ everywhere"). This test pins the post-refactor contract: the import path
+ must not mutate or drop ``rootPath``.
+ """
+ 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",
+ },
+ "CHART2": {
+ "id": "CHART2",
+ "meta": {"chartId": 102, "uuid": "uuid2"},
+ "type": "CHART",
+ },
+ "CHART3": {
+ "id": "CHART3",
+ "meta": {"chartId": 103, "uuid": "uuid3"},
+ "type": "CHART",
+ },
+ },
+ "metadata": {
+ "native_filter_configuration": [
+ {
+ "id": "NATIVE_FILTER-region",
+ "name": "Region",
+ "scope": {
+ # Filter applies only to charts under TAB-revenue,
+ # except chart 102 which is explicitly excluded.
+ "rootPath": ["TAB-revenue"],
+ "excluded": [102],
+ },
+ },
+ {
+ "id": "NATIVE_FILTER-product",
+ "name": "Product",
+ "scope": {
+ # Different filter, different rootPath; must not be
+ # cross-contaminated with the first filter's scope.
+ "rootPath": ["TAB-inventory", "TAB-revenue"],
+ "excluded": [101, 103],
+ },
+ },
+ ],
+ },
+ }
+ chart_ids = {"uuid1": 1, "uuid2": 2, "uuid3": 3}
+ dataset_info: dict[str, dict[str, Any]] = {}
+
+ fixed = update_id_refs(config, chart_ids, dataset_info)
+ filters = fixed["metadata"]["native_filter_configuration"]
+
+ # rootPath uses position keys, not chart IDs — must pass through unchanged.
+ assert filters[0]["scope"]["rootPath"] == ["TAB-revenue"]
+ assert filters[1]["scope"]["rootPath"] == ["TAB-inventory", "TAB-revenue"]
+
+ # excluded uses chart IDs — must be remapped to destination-env IDs.
+ assert filters[0]["scope"]["excluded"] == [2]
+ assert filters[1]["scope"]["excluded"] == [1, 3]
+
+
+def test_update_native_filter_config_default_rootpath_preserved():
+ """
+ The "apply everywhere" default — ``rootPath: ["ROOT_ID"]`` — must also
+ survive untouched. A regression that special-cased this value (e.g. by
+ deleting it) would silently change "apply everywhere" into "apply nowhere"
+ on import, since downstream consumers treat a missing rootPath as empty
+ rather than as the default.
+ """
+ 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": {
+ "native_filter_configuration": [
+ {
+ "id": "NATIVE_FILTER-global",
+ "name": "Global",
+ "scope": {"rootPath": ["ROOT_ID"], "excluded": []},
+ }
+ ],
+ },
+ }
+ chart_ids = {"uuid1": 1}
+ dataset_info: dict[str, dict[str, Any]] = {}
+
+ fixed = update_id_refs(config, chart_ids, dataset_info)
+ scope = fixed["metadata"]["native_filter_configuration"][0]["scope"]
+
+ assert scope["rootPath"] == ["ROOT_ID"]
+ assert scope["excluded"] == []
+
+
def
test_update_id_refs_cross_filter_chart_configuration_key_and_excluded_mapping():
from superset.commands.dashboard.importers.v1.utils import update_id_refs