diff --git a/superset/cli/viz_migrations.py b/superset/cli/viz_migrations.py index c80c3a513..4ddc739cd 100644 --- a/superset/cli/viz_migrations.py +++ b/superset/cli/viz_migrations.py @@ -25,7 +25,9 @@ from superset import db class VizType(str, Enum): AREA = "area" + BAR = "bar" BUBBLE = "bubble" + DIST_BAR = "dist_bar" DUAL_LINE = "dual_line" HEATMAP = "heatmap" LINE = "line" @@ -78,7 +80,9 @@ def migrate(viz_type: VizType, is_downgrade: bool = False) -> None: # pylint: disable=import-outside-toplevel from superset.migrations.shared.migrate_viz.processors import ( MigrateAreaChart, + MigrateBarChart, MigrateBubbleChart, + MigrateDistBarChart, MigrateDualLine, MigrateHeatmapChart, MigrateLineChart, @@ -89,7 +93,9 @@ def migrate(viz_type: VizType, is_downgrade: bool = False) -> None: migrations = { VizType.AREA: MigrateAreaChart, + VizType.BAR: MigrateBarChart, VizType.BUBBLE: MigrateBubbleChart, + VizType.DIST_BAR: MigrateDistBarChart, VizType.DUAL_LINE: MigrateDualLine, VizType.HEATMAP: MigrateHeatmapChart, VizType.LINE: MigrateLineChart, diff --git a/superset/migrations/shared/migrate_viz/processors.py b/superset/migrations/shared/migrate_viz/processors.py index 6df66b9f4..b3504bc28 100644 --- a/superset/migrations/shared/migrate_viz/processors.py +++ b/superset/migrations/shared/migrate_viz/processors.py @@ -109,12 +109,19 @@ class TimeseriesChart(MigrateViz): "show_controls": "show_extra_controls", "x_axis_label": "x_axis_title", "x_axis_format": "x_axis_time_format", + "x_axis_showminmax": "truncateXAxis", "x_ticks_layout": "xAxisLabelRotation", "y_axis_label": "y_axis_title", "y_axis_showminmax": "truncateYAxis", "y_log_scale": "logAxis", } - remove_keys = {"contribution", "show_brush", "show_markers"} + remove_keys = { + "contribution", + "line_interpolation", + "reduce_x_ticks", + "show_brush", + "show_markers", + } def _pre_action(self) -> None: self.data["contributionMode"] = "row" if self.data.get("contribution") else None @@ -156,8 +163,6 @@ class MigrateLineChart(TimeseriesChart): def _pre_action(self) -> None: super()._pre_action() - self.remove_keys.add("line_interpolation") - line_interpolation = self.data.get("line_interpolation") if line_interpolation == "cardinal": self.target_viz_type = "echarts_timeseries_smooth" @@ -190,6 +195,49 @@ class MigrateAreaChart(TimeseriesChart): self.data["opacity"] = 0.7 +class MigrateBarChart(TimeseriesChart): + source_viz_type = "bar" + target_viz_type = "echarts_timeseries_bar" + + def _pre_action(self) -> None: + super()._pre_action() + + self.rename_keys["show_bar_value"] = "show_value" + + self.remove_keys.add("bar_stacked") + + self.data["stack"] = "Stack" if self.data.get("bar_stacked") else None + + +class MigrateDistBarChart(TimeseriesChart): + source_viz_type = "dist_bar" + target_viz_type = "echarts_timeseries_bar" + has_x_axis_control = False + + def _pre_action(self) -> None: + super()._pre_action() + + groupby = self.data.get("groupby") or [] + columns = self.data.get("columns") or [] + if len(groupby) > 0: + # x-axis supports only one value + self.data["x_axis"] = groupby[0] + + self.data["groupby"] = [] + if len(groupby) > 1: + # rest of groupby will go into dimensions + self.data["groupby"] += groupby[1:] + if len(columns) > 0: + self.data["groupby"] += columns + + self.rename_keys["show_bar_value"] = "show_value" + + self.remove_keys.add("columns") + self.remove_keys.add("bar_stacked") + + self.data["stack"] = "Stack" if self.data.get("bar_stacked") else None + + class MigrateBubbleChart(MigrateViz): source_viz_type = "bubble" target_viz_type = "bubble_v2" diff --git a/tests/unit_tests/migrations/viz/nvd3_bar_chart_to_echarts_test.py b/tests/unit_tests/migrations/viz/nvd3_bar_chart_to_echarts_test.py new file mode 100644 index 000000000..a37cd00fc --- /dev/null +++ b/tests/unit_tests/migrations/viz/nvd3_bar_chart_to_echarts_test.py @@ -0,0 +1,64 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from typing import Any + +from superset.migrations.shared.migrate_viz import MigrateBarChart, MigrateDistBarChart +from tests.unit_tests.migrations.viz.utils import ( + migrate_and_assert, + TIMESERIES_SOURCE_FORM_DATA, + TIMESERIES_TARGET_FORM_DATA, +) + + +def test_bar_migration() -> None: + source_form_data: dict[str, Any] = { + "viz_type": "bar", + "show_bar_value": True, + "bar_stacked": True, + } + + target_form_data: dict[str, Any] = { + "form_data_bak": source_form_data, + "viz_type": "echarts_timeseries_bar", + "show_value": True, + "stack": "Stack", + } + source_form_data.update(TIMESERIES_SOURCE_FORM_DATA) + target_form_data.update(TIMESERIES_TARGET_FORM_DATA) + migrate_and_assert(MigrateBarChart, source_form_data, target_form_data) + + +def test_dist_bar_migration() -> None: + source_form_data: dict[str, Any] = { + "viz_type": "dist_bar", + "show_bar_value": True, + "bar_stacked": True, + "groupby": ["column_a", "column_b"], + "columns": ["column_c", "column_d"], + } + + target_form_data: dict[str, Any] = { + "form_data_bak": source_form_data, + "viz_type": "echarts_timeseries_bar", + "show_value": True, + "stack": "Stack", + "x_axis": "column_a", + "groupby": ["column_b", "column_c", "column_d"], + } + source_form_data.update(TIMESERIES_SOURCE_FORM_DATA) + target_form_data.update(TIMESERIES_TARGET_FORM_DATA) + migrate_and_assert(MigrateDistBarChart, source_form_data, target_form_data)