You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2025/08/19 16:44:24 UTC

(superset) 02/04: feat: Complete migration of ALL ECharts control panels to React architecture 🎉

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch move-controls
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 184f800ec10e26bfe890e2e8478e3f8fa2ae007a
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Mon Aug 18 21:25:23 2025 -0700

    feat: Complete migration of ALL ECharts control panels to React architecture 🎉
    
    Migrated 25 chart control panels from legacy config-based to modern React-based:
    
    Core Charts:
    - Pie, Funnel, Sankey, Treemap (already done)
    - BoxPlot, Bubble, Gantt, Gauge, Graph
    - Heatmap, Histogram, Radar, Sunburst, Tree, Waterfall
    
    BigNumber Variants (3):
    - BigNumberTotal
    - BigNumberPeriodOverPeriod
    - BigNumberWithTrendline
    
    Timeseries Variants (7):
    - Area, Step, Line, Bar, Scatter, SmoothLine
    - MixedTimeseries (most complex with dual Y-axes)
    
    Key improvements across all migrations:
    - Direct React components instead of config objects
    - Full TypeScript support with proper types
    - Tab-based organization (Data/Customize/Options)
    - Proper safety checks and validation
    - Conditional rendering for dependent controls
    - Single column handling where needed
    - Modern control components (DndColumnSelect, etc.)
    
    All charts compile successfully with webpack dev server.
    This completes the control panel modernization effort!
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <no...@anthropic.com>
---
 ...BigNumberPeriodOverPeriodControlPanelSimple.tsx |  497 +++++++++
 .../BigNumber/BigNumberPeriodOverPeriod/index.ts   |    2 +-
 .../BigNumberTotalControlPanelSimple.tsx           |  442 ++++++++
 .../src/BigNumber/BigNumberTotal/index.ts          |    2 +-
 .../BigNumberWithTrendlineControlPanelSimple.tsx   |  783 ++++++++++++++
 .../src/BigNumber/BigNumberWithTrendline/index.ts  |    2 +-
 .../BoxPlotControlPanelSimple.tsx}                 |  298 ++++--
 .../plugin-chart-echarts/src/BoxPlot/index.ts      |    2 +-
 .../src/Bubble/BubbleControlPanelSimple.tsx        |  629 +++++++++++
 .../plugin-chart-echarts/src/Bubble/index.ts       |    2 +-
 .../src/Gantt/GanttControlPanelSimple.tsx          |  596 +++++++++++
 .../plugin-chart-echarts/src/Gantt/index.ts        |    2 +-
 .../src/Gauge/GaugeControlPanelSimple.tsx          |  665 ++++++++++++
 .../plugin-chart-echarts/src/Gauge/index.ts        |    2 +-
 .../src/Graph/GraphControlPanelSimple.tsx          |  681 ++++++++++++
 .../plugin-chart-echarts/src/Graph/index.ts        |    2 +-
 .../src/Heatmap/HeatmapControlPanelSimple.tsx      |  754 +++++++++++++
 .../plugin-chart-echarts/src/Heatmap/index.ts      |    2 +-
 .../src/Histogram/HistogramControlPanelSimple.tsx  |  493 +++++++++
 .../plugin-chart-echarts/src/Histogram/index.ts    |    2 +-
 .../MixedTimeseriesControlPanelSimple.tsx          | 1111 ++++++++++++++++++++
 .../src/MixedTimeseries/index.ts                   |    2 +-
 .../RadarControlPanelSimple.tsx}                   |  336 ++++--
 .../plugin-chart-echarts/src/Radar/index.ts        |    2 +-
 .../src/Sankey/SankeyControlPanelSimple.tsx        |   10 +-
 .../src/Sunburst/SunburstControlPanelSimple.tsx    |  538 ++++++++++
 .../plugin-chart-echarts/src/Sunburst/index.ts     |    2 +-
 .../src/Timeseries/Area/AreaControlPanelSimple.tsx |  877 +++++++++++++++
 .../src/Timeseries/Area/index.ts                   |    2 +-
 .../Regular/Bar/BarControlPanelSimple.tsx          | 1075 +++++++++++++++++++
 .../src/Timeseries/Regular/Bar/index.ts            |    2 +-
 .../Regular/Line/LineControlPanelSimple.tsx        |  831 +++++++++++++++
 .../src/Timeseries/Regular/Line/index.ts           |    2 +-
 .../Regular/Scatter/ScatterControlPanelSimple.tsx  |  770 ++++++++++++++
 .../src/Timeseries/Regular/Scatter/index.ts        |    2 +-
 .../SmoothLine/SmoothLineControlPanelSimple.tsx    |  770 ++++++++++++++
 .../src/Timeseries/Regular/SmoothLine/index.ts     |    2 +-
 .../src/Timeseries/Step/StepControlPanelSimple.tsx |  827 +++++++++++++++
 .../src/Timeseries/Step/index.ts                   |    2 +-
 .../src/Tree/TreeControlPanelSimple.tsx            |  548 ++++++++++
 .../plugins/plugin-chart-echarts/src/Tree/index.ts |    2 +-
 .../src/Waterfall/WaterfallControlPanelSimple.tsx  |  574 ++++++++++
 .../plugin-chart-echarts/src/Waterfall/index.ts    |    2 +-
 43 files changed, 13946 insertions(+), 201 deletions(-)

diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/BigNumberPeriodOverPeriodControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/BigNumberPeriodOverPeriodControlPanelSimple.tsx
new file mode 100644
index 0000000000..f136597777
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/BigNumberPeriodOverPeriodControlPanelSimple.tsx
@@ -0,0 +1,497 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t, GenericDataType } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import { DndMetricSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../../src/explore/components/controls/CurrencyControl';
+import ControlHeader from '../../../../../src/explore/components/ControlHeader';
+import Control from '../../../../../src/explore/components/Control';
+import ColumnConfigControl from '../../../../../src/explore/components/controls/ColumnConfigControl';
+import { ColorSchemeEnum } from './types';
+
+interface BigNumberPeriodOverPeriodControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for BigNumber Period-over-Period charts.
+ */
+export const BigNumberPeriodOverPeriodControlPanel: FC<BigNumberPeriodOverPeriodControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row Limit */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Row limit')}
+          description={t('Limit the number of rows that are returned')}
+          hovered
+        />
+        <TextControl
+          value={formValues.row_limit}
+          onChange={handleChange('row_limit')}
+          isInt
+          placeholder="100"
+          controlId="row_limit"
+        />
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Number format */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Number format')}
+            value={formValues.y_axis_format || ''}
+            onChange={handleChange('y_axis_format')}
+            placeholder="SMART_NUMBER"
+            controlId="y_axis_format"
+            renderTrigger
+          />
+        </div>
+
+        {/* Percent Difference format */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Percent Difference format')}
+            value={formValues.percentDifferenceFormat || ''}
+            onChange={handleChange('percentDifferenceFormat')}
+            placeholder="SMART_NUMBER"
+            controlId="percentDifferenceFormat"
+            renderTrigger
+          />
+        </div>
+
+        {/* Currency format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Header Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Big Number Font Size')}
+            value={formValues.header_font_size || 0.2}
+            onChange={handleChange('header_font_size')}
+            choices={[
+              [0.2, t('Tiny')],
+              [0.3, t('Small')],
+              [0.4, t('Normal')],
+              [0.5, t('Large')],
+              [0.6, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Subtitle */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Subtitle')}
+            description={t('Description text that shows up below your Big Number')}
+            value={formValues.subtitle || ''}
+            onChange={handleChange('subtitle')}
+            controlId="subtitle"
+            renderTrigger
+          />
+        </div>
+
+        {/* Subtitle Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Subtitle Font Size')}
+            value={formValues.subtitle_font_size || 0.15}
+            onChange={handleChange('subtitle_font_size')}
+            choices={[
+              [0.125, t('Tiny')],
+              [0.15, t('Small')],
+              [0.2, t('Normal')],
+              [0.3, t('Large')],
+              [0.4, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show Metric Name */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Metric Name')}
+            description={t('Whether to display the metric name')}
+            value={formValues.show_metric_name ?? false}
+            onChange={handleChange('show_metric_name')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Metric Name Font Size - CONDITIONAL */}
+        {formValues.show_metric_name && (
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Metric Name Font Size')}
+              value={formValues.metric_name_font_size || 0.15}
+              onChange={handleChange('metric_name_font_size')}
+              choices={[
+                [0.125, t('Tiny')],
+                [0.15, t('Small')],
+                [0.2, t('Normal')],
+                [0.3, t('Large')],
+                [0.4, t('Huge')],
+              ]}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        {/* Comparison font size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Comparison font size')}
+            value={formValues.subheader_font_size || 0.125}
+            onChange={handleChange('subheader_font_size')}
+            choices={[
+              [0.125, t('Tiny')],
+              [0.15, t('Small')],
+              [0.2, t('Normal')],
+              [0.3, t('Large')],
+              [0.4, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Add color for positive/negative change */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Add color for positive/negative change')}
+            description={t('Add color for positive/negative change')}
+            value={formValues.comparison_color_enabled ?? false}
+            onChange={handleChange('comparison_color_enabled')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Color scheme for comparison - CONDITIONAL */}
+        {formValues.comparison_color_enabled && (
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('color scheme for comparison')}
+              description={t(
+                'Adds color to the chart symbols based on the positive or ' +
+                  'negative change from the comparison value.',
+              )}
+              value={formValues.comparison_color_scheme || ColorSchemeEnum.Green}
+              onChange={handleChange('comparison_color_scheme')}
+              choices={[
+                [ColorSchemeEnum.Green, 'Green for increase, red for decrease'],
+                [ColorSchemeEnum.Red, 'Red for increase, green for decrease'],
+              ]}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        {/* Column Configuration */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Customize columns')}
+            description={t('Further customize how to display each column')}
+            hovered
+          />
+          <ColumnConfigControl
+            value={formValues.column_config || {}}
+            onChange={handleChange('column_config')}
+            configFormLayout={{
+              [GenericDataType.Numeric]: [
+                {
+                  tab: t('General'),
+                  children: [
+                    ['customColumnName'],
+                    ['displayTypeIcon'],
+                    ['visible'],
+                  ],
+                },
+              ],
+            }}
+            columnsPropsObject={{
+              colnames: ['Previous value', 'Delta', 'Percent change'],
+              coltypes: [
+                GenericDataType.Numeric,
+                GenericDataType.Numeric,
+                GenericDataType.Numeric,
+              ],
+            }}
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Big Number with Period-over-Period')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Displays a metric value with comparison to previous period')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(BigNumberPeriodOverPeriodControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[BigNumberPeriodOverPeriodControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 100,
+      label: t('Row limit'),
+    },
+    y_axis_format: {
+      default: '',
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    percentDifferenceFormat: {
+      default: '',
+      label: t('Percent Difference format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    header_font_size: {
+      default: 0.2,
+      label: t('Big Number Font Size'),
+      renderTrigger: true,
+    },
+    subtitle: {
+      default: '',
+      label: t('Subtitle'),
+      renderTrigger: true,
+    },
+    subtitle_font_size: {
+      default: 0.15,
+      label: t('Subtitle Font Size'),
+      renderTrigger: true,
+    },
+    show_metric_name: {
+      default: false,
+      label: t('Show Metric Name'),
+      renderTrigger: true,
+    },
+    metric_name_font_size: {
+      default: 0.15,
+      label: t('Metric Name Font Size'),
+      renderTrigger: true,
+    },
+    subheader_font_size: {
+      default: 0.125,
+      label: t('Comparison font size'),
+      renderTrigger: true,
+    },
+    comparison_color_enabled: {
+      default: false,
+      label: t('Add color for positive/negative change'),
+      renderTrigger: true,
+    },
+    comparison_color_scheme: {
+      default: ColorSchemeEnum.Green,
+      label: t('color scheme for comparison'),
+      renderTrigger: true,
+    },
+    column_config: {
+      default: {},
+      label: t('Customize columns'),
+      renderTrigger: true,
+    },
+  },
+  formDataOverrides: (formData: any) => ({
+    ...formData,
+    metric: formData.metric,
+  }),
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/index.ts
index 53ab44c2aa..3f84766995 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/index.ts
@@ -18,7 +18,7 @@
  */
 import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './BigNumberPeriodOverPeriodControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/BigNumberTotalControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/BigNumberTotalControlPanelSimple.tsx
new file mode 100644
index 0000000000..3d9903dd74
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/BigNumberTotalControlPanelSimple.tsx
@@ -0,0 +1,442 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { GenericDataType, SMART_DATE_ID, t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  D3_FORMAT_DOCS,
+  D3_TIME_FORMAT_OPTIONS,
+  Dataset,
+} from '@superset-ui/chart-controls';
+import { DndMetricSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../../src/explore/components/controls/CurrencyControl';
+import ControlHeader from '../../../../../src/explore/components/ControlHeader';
+import Control from '../../../../../src/explore/components/Control';
+import ConditionalFormattingControl from '../../../../../src/explore/components/controls/ConditionalFormattingControl';
+
+interface BigNumberTotalControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for BigNumber Total charts.
+ */
+export const BigNumberTotalControlPanel: FC<BigNumberTotalControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Time Column */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Time Column')}
+          description={t('Select the time column for temporal filtering')}
+          hovered
+        />
+        <SelectControl
+          value={formValues.granularity || null}
+          onChange={handleChange('granularity')}
+          choices={safeColumns
+            .filter((col: any) => col.is_dttm)
+            .map((col: any) => [col.column_name, col.verbose_name || col.column_name])}
+          clearable
+          placeholder={t('Select time column')}
+          renderTrigger
+        />
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Header Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Big Number Font Size')}
+            value={formValues.header_font_size || 0.4}
+            onChange={handleChange('header_font_size')}
+            choices={[
+              [0.2, t('Tiny')],
+              [0.3, t('Small')],
+              [0.4, t('Normal')],
+              [0.5, t('Large')],
+              [0.6, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Subtitle */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Subtitle')}
+            description={t('Description text that shows up below your Big Number')}
+            value={formValues.subtitle || ''}
+            onChange={handleChange('subtitle')}
+            controlId="subtitle"
+            renderTrigger
+          />
+        </div>
+
+        {/* Subtitle Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Subtitle Font Size')}
+            value={formValues.subtitle_font_size || 0.15}
+            onChange={handleChange('subtitle_font_size')}
+            choices={[
+              [0.125, t('Tiny')],
+              [0.15, t('Small')],
+              [0.2, t('Normal')],
+              [0.3, t('Large')],
+              [0.4, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show Metric Name */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Metric Name')}
+            description={t('Whether to display the metric name')}
+            value={formValues.show_metric_name ?? false}
+            onChange={handleChange('show_metric_name')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Metric Name Font Size - CONDITIONAL */}
+        {formValues.show_metric_name && (
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Metric Name Font Size')}
+              value={formValues.metric_name_font_size || 0.15}
+              onChange={handleChange('metric_name_font_size')}
+              choices={[
+                [0.125, t('Tiny')],
+                [0.15, t('Small')],
+                [0.2, t('Normal')],
+                [0.3, t('Large')],
+                [0.4, t('Huge')],
+              ]}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+      </div>
+
+      {/* Formatting Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Formatting')}</h4>
+
+        {/* Number format */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Number format')}
+            value={formValues.y_axis_format || ''}
+            onChange={handleChange('y_axis_format')}
+            placeholder="SMART_NUMBER"
+            controlId="y_axis_format"
+            renderTrigger
+          />
+        </div>
+
+        {/* Currency format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Date format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Date format')}
+            description={D3_FORMAT_DOCS}
+            value={formValues.time_format || SMART_DATE_ID}
+            onChange={handleChange('time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Force Date Format */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Force date format')}
+            description={t(
+              'Use date formatting even when metric value is not a timestamp',
+            )}
+            value={formValues.force_timestamp_formatting ?? false}
+            onChange={handleChange('force_timestamp_formatting')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Conditional Formatting */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Conditional Formatting')}
+            description={t('Apply conditional color formatting to metric')}
+            hovered
+          />
+          <ConditionalFormattingControl
+            value={formValues.conditional_formatting || []}
+            onChange={handleChange('conditional_formatting')}
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Big Number')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Displays a single metric value in a large font')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(BigNumberTotalControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[BigNumberTotalControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    granularity: {
+      default: null,
+      label: t('Time Column'),
+    },
+    header_font_size: {
+      default: 0.4,
+      label: t('Big Number Font Size'),
+      renderTrigger: true,
+    },
+    subtitle: {
+      default: '',
+      label: t('Subtitle'),
+      renderTrigger: true,
+    },
+    subtitle_font_size: {
+      default: 0.15,
+      label: t('Subtitle Font Size'),
+      renderTrigger: true,
+    },
+    show_metric_name: {
+      default: false,
+      label: t('Show Metric Name'),
+      renderTrigger: true,
+    },
+    metric_name_font_size: {
+      default: 0.15,
+      label: t('Metric Name Font Size'),
+      renderTrigger: true,
+    },
+    y_axis_format: {
+      default: '',
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    time_format: {
+      default: SMART_DATE_ID,
+      label: t('Date format'),
+      renderTrigger: true,
+    },
+    force_timestamp_formatting: {
+      default: false,
+      label: t('Force date format'),
+      renderTrigger: true,
+    },
+    conditional_formatting: {
+      default: [],
+      label: t('Conditional Formatting'),
+      renderTrigger: true,
+    },
+  },
+  formDataOverrides: (formData: any) => ({
+    ...formData,
+    metric: formData.metric,
+  }),
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts
index d77ea1e4cd..ff057179e1 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { t, Behavior } from '@superset-ui/core';
-import controlPanel from './controlPanel';
+import controlPanel from './BigNumberTotalControlPanelSimple';
 import transformProps from './transformProps';
 import buildQuery from './buildQuery';
 import example1 from './images/BigNumber.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/BigNumberWithTrendlineControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/BigNumberWithTrendlineControlPanelSimple.tsx
new file mode 100644
index 0000000000..2590b485eb
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/BigNumberWithTrendlineControlPanelSimple.tsx
@@ -0,0 +1,783 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { SMART_DATE_ID, t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  D3_FORMAT_DOCS,
+  D3_TIME_FORMAT_OPTIONS,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../../src/explore/components/controls/CurrencyControl';
+import ColorPickerControl from '../../../../../src/explore/components/controls/ColorPickerControl';
+import ControlHeader from '../../../../../src/explore/components/ControlHeader';
+
+interface BigNumberWithTrendlineControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for BigNumber with Trendline charts.
+ */
+export const BigNumberWithTrendlineControlPanel: FC<BigNumberWithTrendlineControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Temporal X-Axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Temporal X-Axis')}
+          description={t('Column used for temporal grouping')}
+          hovered
+        />
+        <DndColumnSelect
+          value={formValues.x_axis ? [formValues.x_axis] : []}
+          onChange={(val: any) => {
+            const singleValue = Array.isArray(val) ? val[0] : val;
+            handleChange('x_axis')(singleValue);
+          }}
+          options={safeColumns.filter((col: any) => col.is_dttm)}
+          name="x_axis"
+          label=""
+          multi={false}
+          canDelete
+          ghostButtonText={t('Add temporal column')}
+          type="DndColumnSelect"
+          actions={actions}
+        />
+      </div>
+
+      {/* Time Grain */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Time Grain')}
+          description={t('The time granularity for the visualization')}
+          hovered
+        />
+        <SelectControl
+          value={formValues.time_grain_sqla || null}
+          onChange={handleChange('time_grain_sqla')}
+          choices={[
+            [null, t('Auto')],
+            ['PT1S', t('Second')],
+            ['PT1M', t('Minute')],
+            ['PT5M', t('5 Minutes')],
+            ['PT10M', t('10 Minutes')],
+            ['PT15M', t('15 Minutes')],
+            ['PT30M', t('30 Minutes')],
+            ['PT1H', t('Hour')],
+            ['P1D', t('Day')],
+            ['P1W', t('Week')],
+            ['P1M', t('Month')],
+            ['P3M', t('Quarter')],
+            ['P1Y', t('Year')],
+          ]}
+          clearable
+          renderTrigger
+        />
+      </div>
+
+      {/* Aggregation */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Aggregation')}
+          description={t('Aggregation function to apply')}
+          hovered
+        />
+        <SelectControl
+          value={formValues.time_range_endpoints || null}
+          onChange={handleChange('time_range_endpoints')}
+          choices={[
+            [null, t('Auto')],
+            ['inclusive', t('Inclusive of both endpoints')],
+            ['exclusive', t('Exclusive of both endpoints')],
+          ]}
+          clearable
+          renderTrigger
+        />
+      </div>
+
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+    </div>
+  );
+
+  // Options tab content (labeled as "Options" in original)
+  const optionsTabContent = (
+    <div>
+      {/* Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Comparison Options')}</h4>
+
+        {/* Comparison Period Lag */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Comparison Period Lag')}
+            description={t(
+              'Based on granularity, number of time periods to compare against',
+            )}
+            value={formValues.compare_lag || ''}
+            onChange={handleChange('compare_lag')}
+            isInt
+            controlId="compare_lag"
+          />
+        </div>
+
+        {/* Comparison suffix */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Comparison suffix')}
+            description={t('Suffix to apply after the percentage display')}
+            value={formValues.compare_suffix || ''}
+            onChange={handleChange('compare_suffix')}
+            controlId="compare_suffix"
+          />
+        </div>
+
+        {/* Show Timestamp */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Timestamp')}
+            description={t('Whether to display the timestamp')}
+            value={formValues.show_timestamp ?? false}
+            onChange={handleChange('show_timestamp')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show Trend Line */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Trend Line')}
+            description={t('Whether to display the trend line')}
+            value={formValues.show_trend_line ?? true}
+            onChange={handleChange('show_trend_line')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Start y-axis at 0 */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Start y-axis at 0')}
+            description={t(
+              'Start y-axis at zero. Uncheck to start y-axis at minimum value in the data.',
+            )}
+            value={formValues.start_y_axis_at_zero ?? true}
+            onChange={handleChange('start_y_axis_at_zero')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Fix to selected Time Range - CONDITIONAL */}
+        {formValues.time_range && formValues.time_range !== 'No filter' && (
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Fix to selected Time Range')}
+              description={t(
+                'Fix the trend line to the full time range specified in case filtered results do not include the start or end dates',
+              )}
+              value={formValues.time_range_fixed ?? false}
+              onChange={handleChange('time_range_fixed')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Picker */}
+        <div style={{ marginBottom: 16 }}>
+          <ColorPickerControl
+            value={formValues.color_picker}
+            onChange={handleChange('color_picker')}
+          />
+        </div>
+
+        {/* Header Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Big Number Font Size')}
+            value={formValues.header_font_size || 0.4}
+            onChange={handleChange('header_font_size')}
+            choices={[
+              [0.2, t('Tiny')],
+              [0.3, t('Small')],
+              [0.4, t('Normal')],
+              [0.5, t('Large')],
+              [0.6, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Subheader Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Subheader Font Size')}
+            value={formValues.subheader_font_size || 0.15}
+            onChange={handleChange('subheader_font_size')}
+            choices={[
+              [0.125, t('Tiny')],
+              [0.15, t('Small')],
+              [0.2, t('Normal')],
+              [0.3, t('Large')],
+              [0.4, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Subtitle */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Subtitle')}
+            description={t('Description text that shows up below your Big Number')}
+            value={formValues.subtitle || ''}
+            onChange={handleChange('subtitle')}
+            controlId="subtitle"
+            renderTrigger
+          />
+        </div>
+
+        {/* Subtitle Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Subtitle Font Size')}
+            value={formValues.subtitle_font_size || 0.15}
+            onChange={handleChange('subtitle_font_size')}
+            choices={[
+              [0.125, t('Tiny')],
+              [0.15, t('Small')],
+              [0.2, t('Normal')],
+              [0.3, t('Large')],
+              [0.4, t('Huge')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show Metric Name */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Metric Name')}
+            description={t('Whether to display the metric name')}
+            value={formValues.show_metric_name ?? false}
+            onChange={handleChange('show_metric_name')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Metric Name Font Size - CONDITIONAL */}
+        {formValues.show_metric_name && (
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Metric Name Font Size')}
+              value={formValues.metric_name_font_size || 0.15}
+              onChange={handleChange('metric_name_font_size')}
+              choices={[
+                [0.125, t('Tiny')],
+                [0.15, t('Small')],
+                [0.2, t('Normal')],
+                [0.3, t('Large')],
+                [0.4, t('Huge')],
+              ]}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+      </div>
+
+      {/* Formatting Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Formatting')}</h4>
+
+        {/* Number format */}
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Number format')}
+            value={formValues.y_axis_format || ''}
+            onChange={handleChange('y_axis_format')}
+            placeholder="SMART_NUMBER"
+            controlId="y_axis_format"
+            renderTrigger
+          />
+        </div>
+
+        {/* Currency format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Date format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Date format')}
+            description={D3_FORMAT_DOCS}
+            value={formValues.time_format || SMART_DATE_ID}
+            onChange={handleChange('time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Force Date Format */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Force date format')}
+            description={t(
+              'Use date formatting even when metric value is not a timestamp',
+            )}
+            value={formValues.force_timestamp_formatting ?? false}
+            onChange={handleChange('force_timestamp_formatting')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Advanced Analytics Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Advanced Analytics')}</h4>
+
+        {/* Rolling Window subsection */}
+        <div style={{ marginBottom: 16 }}>
+          <h5>{t('Rolling Window')}</h5>
+
+          {/* Rolling Function */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Rolling Function')}
+              description={t(
+                'Defines a rolling window function to apply, works along ' +
+                  'with the [Periods] text box',
+              )}
+              value={formValues.rolling_type || 'None'}
+              onChange={handleChange('rolling_type')}
+              choices={[
+                ['None', t('None')],
+                ['mean', t('mean')],
+                ['sum', t('sum')],
+                ['std', t('std')],
+                ['cumsum', t('cumsum')],
+              ]}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Periods */}
+          <div style={{ marginBottom: 16 }}>
+            <TextControl
+              label={t('Periods')}
+              description={t(
+                'Defines the size of the rolling window function, ' +
+                  'relative to the time granularity selected',
+              )}
+              value={formValues.rolling_periods || ''}
+              onChange={handleChange('rolling_periods')}
+              isInt
+              controlId="rolling_periods"
+            />
+          </div>
+
+          {/* Min Periods */}
+          <div style={{ marginBottom: 16 }}>
+            <TextControl
+              label={t('Min Periods')}
+              description={t(
+                'The minimum number of rolling periods required to show ' +
+                  'a value. For instance if you do a cumulative sum on 7 days ' +
+                  'you may want your "Min Period" to be 7, so that all data points ' +
+                  'shown are the total of 7 periods. This will hide the "ramp up" ' +
+                  'taking place over the first 7 periods',
+              )}
+              value={formValues.min_periods || ''}
+              onChange={handleChange('min_periods')}
+              isInt
+              controlId="min_periods"
+            />
+          </div>
+        </div>
+
+        {/* Resample subsection */}
+        <div style={{ marginBottom: 16 }}>
+          <h5>{t('Resample')}</h5>
+
+          {/* Rule */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Rule')}
+              description={t('Pandas resample rule')}
+              value={formValues.resample_rule || null}
+              onChange={handleChange('resample_rule')}
+              choices={[
+                ['1T', t('1 minutely frequency')],
+                ['1H', t('1 hourly frequency')],
+                ['1D', t('1 calendar day frequency')],
+                ['7D', t('7 calendar day frequency')],
+                ['1MS', t('1 month start frequency')],
+                ['1M', t('1 month end frequency')],
+                ['1AS', t('1 year start frequency')],
+                ['1A', t('1 year end frequency')],
+              ]}
+              freeForm
+              clearable
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Fill method */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Fill method')}
+              description={t('Pandas resample method')}
+              value={formValues.resample_method || null}
+              onChange={handleChange('resample_method')}
+              choices={[
+                ['asfreq', t('Null imputation')],
+                ['zerofill', t('Zero imputation')],
+                ['linear', t('Linear interpolation')],
+                ['ffill', t('Forward values')],
+                ['bfill', t('Backward values')],
+                ['median', t('Median values')],
+                ['mean', t('Mean values')],
+                ['sum', t('Sum values')],
+              ]}
+              freeForm
+              clearable
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'options',
+      label: t('Options'),
+      children: optionsTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Big Number with Trendline')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Displays a metric value with a time-series trend chart')}
+        </div>
+      </div>
+
+      {/* Tabs for Data, Options, and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(BigNumberWithTrendlineControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[BigNumberWithTrendlineControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    x_axis: {
+      default: null,
+      label: t('Temporal X-Axis'),
+    },
+    time_grain_sqla: {
+      default: null,
+      label: t('Time Grain'),
+    },
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    compare_lag: {
+      default: '',
+      label: t('Comparison Period Lag'),
+    },
+    compare_suffix: {
+      default: '',
+      label: t('Comparison suffix'),
+    },
+    show_timestamp: {
+      default: false,
+      label: t('Show Timestamp'),
+      renderTrigger: true,
+    },
+    show_trend_line: {
+      default: true,
+      label: t('Show Trend Line'),
+      renderTrigger: true,
+    },
+    start_y_axis_at_zero: {
+      default: true,
+      label: t('Start y-axis at 0'),
+      renderTrigger: true,
+    },
+    time_range_fixed: {
+      default: false,
+      label: t('Fix to selected Time Range'),
+      renderTrigger: true,
+    },
+    color_picker: {
+      default: undefined,
+      label: t('Color Picker'),
+      renderTrigger: true,
+    },
+    header_font_size: {
+      default: 0.4,
+      label: t('Big Number Font Size'),
+      renderTrigger: true,
+    },
+    subheader_font_size: {
+      default: 0.15,
+      label: t('Subheader Font Size'),
+      renderTrigger: true,
+    },
+    subtitle: {
+      default: '',
+      label: t('Subtitle'),
+      renderTrigger: true,
+    },
+    subtitle_font_size: {
+      default: 0.15,
+      label: t('Subtitle Font Size'),
+      renderTrigger: true,
+    },
+    show_metric_name: {
+      default: false,
+      label: t('Show Metric Name'),
+      renderTrigger: true,
+    },
+    metric_name_font_size: {
+      default: 0.15,
+      label: t('Metric Name Font Size'),
+      renderTrigger: true,
+    },
+    y_axis_format: {
+      default: '',
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    time_format: {
+      default: SMART_DATE_ID,
+      label: t('Date format'),
+      renderTrigger: true,
+    },
+    force_timestamp_formatting: {
+      default: false,
+      label: t('Force date format'),
+      renderTrigger: true,
+    },
+    rolling_type: {
+      default: 'None',
+      label: t('Rolling Function'),
+      renderTrigger: true,
+    },
+    rolling_periods: {
+      default: '',
+      label: t('Periods'),
+    },
+    min_periods: {
+      default: '',
+      label: t('Min Periods'),
+    },
+    resample_rule: {
+      default: null,
+      label: t('Rule'),
+      renderTrigger: true,
+    },
+    resample_method: {
+      default: null,
+      label: t('Fill method'),
+      renderTrigger: true,
+    },
+  },
+  formDataOverrides: (formData: any) => ({
+    ...formData,
+    metric: formData.metric,
+  }),
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts
index 4379c88e63..31cf60eacb 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { t, Behavior } from '@superset-ui/core';
-import controlPanel from './controlPanel';
+import controlPanel from './BigNumberWithTrendlineControlPanelSimple';
 import transformProps from './transformProps';
 import buildQuery from './buildQuery';
 import example from './images/Big_Number_Trendline.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/BoxPlotControlPanelSimple.tsx
similarity index 50%
copy from superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
copy to superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/BoxPlotControlPanelSimple.tsx
index 1372757963..256326165e 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/BoxPlotControlPanelSimple.tsx
@@ -17,22 +17,24 @@
  * under the License.
  */
 import { FC, useState } from 'react';
-import { t, validateNonEmpty } from '@superset-ui/core';
+import { t } from '@superset-ui/core';
 import { Tabs } from 'antd';
 import {
   ColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
 } from '@superset-ui/chart-controls';
-
-// Direct component imports
 import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
 import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
 import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
 import TextControl from '../../../../src/explore/components/controls/TextControl';
-import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
 import ControlHeader from '../../../../src/explore/components/ControlHeader';
 import Control from '../../../../src/explore/components/Control';
 
-interface SankeyControlPanelProps {
+interface BoxPlotControlPanelProps {
   onChange?: (field: string, value: any) => void;
   value?: Record<string, any>;
   datasource?: any;
@@ -42,9 +44,9 @@ interface SankeyControlPanelProps {
 }
 
 /**
- * A modern React component-based control panel for Sankey charts.
+ * A modern React component-based control panel for Box Plot charts.
  */
-export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
+export const BoxPlotControlPanel: FC<BoxPlotControlPanelProps> = ({
   onChange,
   value,
   datasource,
@@ -86,30 +88,37 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
   // Get form values
   const formValues = form_data || value || {};
 
+  // Helper to check if time_grain_sqla should be visible
+  const shouldShowTimeGrain = () => {
+    return (formValues.columns || []).some((col: any) => {
+      if (typeof col === 'string') {
+        const column = safeColumns.find(c => c.column_name === col);
+        return column?.is_dttm;
+      }
+      return col?.is_dttm || col?.sqlExpression?.includes('date') || col?.sqlExpression?.includes('time');
+    });
+  };
+
   // Data tab content
   const dataTabContent = (
     <div>
-      {/* Source Column */}
+      {/* Distribute across (Columns) */}
       <div style={{ marginBottom: 16 }}>
         <ControlHeader
-          label={t('Source')}
-          description={t('The column to be used as the source of the edge.')}
+          label={t('Distribute across')}
+          description={t('Columns to calculate distribution across.')}
           hovered
         />
         {safeColumns.length > 0 ? (
           <DndColumnSelect
-            value={formValues.source ? [formValues.source] : []}
-            onChange={(val: any) => {
-              // Source is single select, so take first value
-              const sourceValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
-              handleChange('source')(sourceValue);
-            }}
+            value={formValues.columns || []}
+            onChange={handleChange('columns')}
             options={safeColumns}
-            name="source"
+            name="columns"
             label=""
-            multi={false}
+            multi
             canDelete
-            ghostButtonText={t('Select source column')}
+            ghostButtonText={t('Add column')}
             type="DndColumnSelect"
             actions={actions}
           />
@@ -120,52 +129,80 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
         )}
       </div>
 
-      {/* Target Column */}
+      {/* Time Grain - Only show if temporal columns are selected */}
+      {shouldShowTimeGrain() && (
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time Grain')}
+            description={t('Time granularity for temporal grouping')}
+            hovered
+          />
+          <SelectControl
+            value={formValues.time_grain_sqla || null}
+            onChange={handleChange('time_grain_sqla')}
+            choices={[
+              ['PT1S', t('Second')],
+              ['PT1M', t('Minute')],
+              ['PT5M', t('5 minute')],
+              ['PT10M', t('10 minute')],
+              ['PT15M', t('15 minute')],
+              ['PT30M', t('30 minute')],
+              ['PT1H', t('Hour')],
+              ['P1D', t('Day')],
+              ['P1W', t('Week')],
+              ['P1M', t('Month')],
+              ['P3M', t('Quarter')],
+              ['P1Y', t('Year')],
+            ]}
+            clearable
+            renderTrigger
+            hovered
+          />
+        </div>
+      )}
+
+      {/* Dimensions (Group by) */}
       <div style={{ marginBottom: 16 }}>
         <ControlHeader
-          label={t('Target')}
-          description={t('The column to be used as the target of the edge.')}
+          label={t('Dimensions')}
+          description={t('Categories to group by on the x-axis.')}
           hovered
         />
         {safeColumns.length > 0 ? (
           <DndColumnSelect
-            value={formValues.target ? [formValues.target] : []}
-            onChange={(val: any) => {
-              // Target is single select, so take first value
-              const targetValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
-              handleChange('target')(targetValue);
-            }}
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
             options={safeColumns}
-            name="target"
+            name="groupby"
             label=""
-            multi={false}
+            multi
             canDelete
-            ghostButtonText={t('Select target column')}
+            ghostButtonText={t('Add dimension')}
             type="DndColumnSelect"
             actions={actions}
           />
         ) : (
           <div style={{ padding: '10px' }}>
-            {t('No columns available. Please select a dataset first.')}
+            {t('No columns available for grouping.')}
           </div>
         )}
       </div>
 
-      {/* Metric */}
+      {/* Metrics */}
       <div style={{ marginBottom: 16 }}>
         <ControlHeader
-          label={t('Metric')}
-          description={t('Metric to display')}
+          label={t('Metrics')}
+          description={t('Metrics to display')}
           hovered
         />
         {safeDataSource && safeDataSource.columns ? (
           <DndMetricSelect
-            value={formValues.metric}
-            onChange={handleChange('metric')}
+            value={formValues.metrics || []}
+            onChange={handleChange('metrics')}
             datasource={safeDataSource}
-            name="metric"
+            name="metrics"
             label=""
-            multi={false}
+            multi={true}
             savedMetrics={safeMetrics}
           />
         ) : (
@@ -189,7 +226,7 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             formData={formValues}
             name="adhoc_filters"
             savedMetrics={safeMetrics}
-            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            selectedMetrics={formValues.metrics || []}
             type="DndFilterSelect"
             actions={actions}
           />
@@ -200,8 +237,22 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
         )}
       </div>
 
-      {/* Row limit and Sort by metric */}
+      {/* Row and Series Limits */}
       <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Series limit')}
+            description={t('Limit number of series that are displayed')}
+            hovered
+          />
+          <TextControl
+            value={formValues.series_limit}
+            onChange={handleChange('series_limit')}
+            isInt
+            placeholder="25"
+            controlId="series_limit"
+          />
+        </div>
         <div style={{ flex: 1 }}>
           <ControlHeader
             label={t('Row limit')}
@@ -212,21 +263,53 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             value={formValues.row_limit}
             onChange={handleChange('row_limit')}
             isInt
-            placeholder="100"
+            placeholder="1000"
             controlId="row_limit"
           />
         </div>
-        <div style={{ flex: 1 }}>
-          <CheckboxControl
-            label={t('Sort by metric')}
-            description={t(
-              'Whether to sort results by the selected metric in descending order',
-            )}
-            value={formValues.sort_by_metric ?? true}
-            onChange={handleChange('sort_by_metric')}
-            hovered
+      </div>
+
+      {/* Series limit metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Series limit metric')}
+          description={t('Metric used to order the series in the limit')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.series_limit_metric}
+            onChange={handleChange('series_limit_metric')}
+            datasource={safeDataSource}
+            name="series_limit_metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
           />
-        </div>
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Whisker Options */}
+      <div style={{ marginBottom: 16 }}>
+        <SelectControl
+          label={t('Whisker/outlier options')}
+          description={t('Determines how whiskers and outliers are calculated.')}
+          value={formValues.whiskerOptions || 'Tukey'}
+          onChange={handleChange('whiskerOptions')}
+          choices={[
+            ['Tukey', t('Tukey')],
+            ['Min/max (no outliers)', t('Min/max (no outliers)')],
+            ['2/98 percentiles', t('2/98 percentiles')],
+            ['5/95 percentiles', t('5/95 percentiles')],
+            ['9/91 percentiles', t('9/91 percentiles')],
+            ['10/90 percentiles', t('10/90 percentiles')],
+          ]}
+          clearable={false}
+          renderTrigger
+          hovered
+        />
       </div>
     </div>
   );
@@ -259,6 +342,54 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             );
           })()}
         </div>
+
+        {/* X Tick Layout */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('X Tick Layout')}
+            description={t('The way the ticks are laid out on the X-axis')}
+            value={formValues.x_ticks_layout || 'auto'}
+            onChange={handleChange('x_ticks_layout')}
+            choices={[
+              ['auto', t('auto')],
+              ['flat', t('flat')],
+              ['45°', '45°'],
+              ['90°', '90°'],
+              ['staggered', t('staggered')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Number Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Number format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.number_format || 'SMART_NUMBER'}
+            onChange={handleChange('number_format')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Date Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Date format')}
+            description={D3_FORMAT_DOCS}
+            value={formValues.date_format || 'smart_date'}
+            onChange={handleChange('date_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
       </div>
     </div>
   );
@@ -282,10 +413,10 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
       {/* Chart/Viz Type Picker */}
       <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
         <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
-          {t('Sankey Chart')}
+          {t('Box Plot')}
         </div>
         <div style={{ fontSize: '12px', opacity: 0.65 }}>
-          {t('Visualize flow data as a Sankey diagram')}
+          {t('Compare distributions across multiple groups with quartiles, median, and outliers')}
         </div>
       </div>
 
@@ -301,7 +432,7 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
 };
 
 // Mark this component as a modern panel
-(SankeyControlPanel as any).isModernPanel = true;
+(BoxPlotControlPanel as any).isModernPanel = true;
 
 // Create a config that wraps our React component
 const config = {
@@ -309,41 +440,68 @@ const config = {
     {
       label: null,
       expanded: true,
-      controlSetRows: [[SankeyControlPanel as any]],
+      controlSetRows: [[BoxPlotControlPanel as any]],
     },
   ],
   controlOverrides: {
-    source: {
-      default: null,
-      label: t('Source'),
-      validators: [validateNonEmpty],
+    columns: {
+      default: [],
+      label: t('Distribute across'),
+      multi: true,
     },
-    target: {
+    time_grain_sqla: {
       default: null,
-      label: t('Target'),
-      validators: [validateNonEmpty],
+      label: t('Time Grain'),
     },
-    metric: {
-      default: null,
-      label: t('Metric'),
+    groupby: {
+      default: [],
+      label: t('Dimensions'),
+    },
+    metrics: {
+      default: [],
+      label: t('Metrics'),
     },
     adhoc_filters: {
       default: [],
       label: t('Filters'),
     },
+    series_limit: {
+      default: 25,
+      label: t('Series limit'),
+    },
     row_limit: {
-      default: 100,
+      default: 1000,
       label: t('Row limit'),
     },
-    sort_by_metric: {
-      default: true,
-      label: t('Sort by metric'),
+    series_limit_metric: {
+      default: null,
+      label: t('Series limit metric'),
+    },
+    whiskerOptions: {
+      default: 'Tukey',
+      label: t('Whisker/outlier options'),
+      renderTrigger: true,
     },
     color_scheme: {
       default: 'supersetColors',
       label: t('Color scheme'),
       renderTrigger: true,
     },
+    x_ticks_layout: {
+      default: 'auto',
+      label: t('X Tick Layout'),
+      renderTrigger: true,
+    },
+    number_format: {
+      default: 'SMART_NUMBER',
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    date_format: {
+      default: 'smart_date',
+      label: t('Date format'),
+      renderTrigger: true,
+    },
   },
 };
 
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts
index a379832f9e..511c7a56f5 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/index.ts
@@ -18,7 +18,7 @@
  */
 import { Behavior, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './BoxPlotControlPanelSimple';
 import transformProps from './transformProps';
 import example from './images/BoxPlot.jpg';
 import thumbnail from './images/thumbnail.png';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/BubbleControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/BubbleControlPanelSimple.tsx
new file mode 100644
index 0000000000..db63dd5a0c
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/BubbleControlPanelSimple.tsx
@@ -0,0 +1,629 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+  formatSelectOptions,
+  sections,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../src/explore/components/controls/SliderControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import { defaultXAxis } from '../defaults';
+
+interface BubbleControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Bubble charts.
+ */
+export const BubbleControlPanel: FC<BubbleControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Helper for single column selection (series, entity)
+  const handleSingleColumnChange = (field: string) => (val: any) => {
+    const singleValue = Array.isArray(val) ? val[0] : val;
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, singleValue);
+    } else if (onChange) {
+      onChange(field, singleValue);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Series */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Series')}
+          description={t('Columns to group by')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.series ? [formValues.series] : []}
+            onChange={handleSingleColumnChange('series')}
+            options={safeColumns}
+            name="series"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Add series')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Entity */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Entity')}
+          description={t('Entity ID column')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.entity ? [formValues.entity] : []}
+            onChange={handleSingleColumnChange('entity')}
+            options={safeColumns}
+            name="entity"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Add entity')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available.')}
+          </div>
+        )}
+      </div>
+
+      {/* X Axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('X Axis')}
+          description={t('Metric for X axis')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.x}
+            onChange={handleChange('x')}
+            datasource={safeDataSource}
+            name="x"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Y Axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Y Axis')}
+          description={t('Metric for Y axis')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.y}
+            onChange={handleChange('y')}
+            datasource={safeDataSource}
+            name="y"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Size */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Bubble Size')}
+          description={t('Metric for bubble size')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.size}
+            onChange={handleChange('size')}
+            datasource={safeDataSource}
+            name="size"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={[formValues.x, formValues.y, formValues.size].filter(Boolean)}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit and Order by */}
+      <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limit the number of rows that are returned')}
+            hovered
+          />
+          <TextControl
+            value={formValues.row_limit}
+            onChange={handleChange('row_limit')}
+            isInt
+            placeholder="100"
+            controlId="row_limit"
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Order descending')}
+            description={t('Sort results by order by descending')}
+            value={formValues.order_desc ?? true}
+            onChange={handleChange('order_desc')}
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Show Legend checkbox */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Max Bubble Size */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Max Bubble Size')}
+            description={t('Maximum size of bubbles')}
+            value={formValues.max_bubble_size || '25'}
+            onChange={handleChange('max_bubble_size')}
+            choices={formatSelectOptions([
+              '5',
+              '10',
+              '15',
+              '25',
+              '50',
+              '75',
+              '100',
+            ])}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Bubble Opacity */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Bubble Opacity')}
+            description={t('Opacity of bubbles, 0 means completely transparent, 1 means opaque')}
+            renderTrigger
+            hovered
+          />
+          <SliderControl
+            value={formValues.opacity || 0.6}
+            onChange={handleChange('opacity')}
+            {...{ min: 0, max: 1, step: 0.1 }}
+          />
+        </div>
+
+        {/* Tooltip Size Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Bubble size number format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.tooltipSizeFormat || 'SMART_NUMBER'}
+            onChange={handleChange('tooltipSizeFormat')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* X Axis Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('X Axis')}</h4>
+
+        {/* X Axis Title */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('X Axis Title')}
+            description={t('Title for the X axis')}
+            hovered
+          />
+          <TextControl
+            value={formValues.x_axis_label || ''}
+            onChange={handleChange('x_axis_label')}
+            placeholder={t('X Axis Title')}
+            controlId="x_axis_label"
+          />
+        </div>
+
+        {/* X Axis Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('X Axis Format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.xAxisFormat || 'SMART_NUMBER'}
+            onChange={handleChange('xAxisFormat')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Logarithmic X-axis */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Logarithmic x-axis')}
+            description={t('Use logarithmic scale for X axis')}
+            value={formValues.logXAxis ?? false}
+            onChange={handleChange('logXAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Y Axis Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Y Axis')}</h4>
+
+        {/* Y Axis Title */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Y Axis Title')}
+            description={t('Title for the Y axis')}
+            hovered
+          />
+          <TextControl
+            value={formValues.y_axis_label || ''}
+            onChange={handleChange('y_axis_label')}
+            placeholder={t('Y Axis Title')}
+            controlId="y_axis_label"
+          />
+        </div>
+
+        {/* Y Axis Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Y Axis Format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.yAxisFormat || 'SMART_NUMBER'}
+            onChange={handleChange('yAxisFormat')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Logarithmic Y-axis */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Logarithmic y-axis')}
+            description={t('Use logarithmic scale for Y axis')}
+            value={formValues.logYAxis ?? false}
+            onChange={handleChange('logYAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Truncate Y Axis */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Truncate Y Axis')}
+            description={t('Truncate Y Axis. Can be overridden by specifying a min or max bound.')}
+            value={formValues.truncateYAxis ?? false}
+            onChange={handleChange('truncateYAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Bubble Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualizes a metric across three dimensions of data in a single chart (X axis, Y axis, and bubble size). Bubbles from the same group can be showcased using bubble color.')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(BubbleControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[BubbleControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    series: {
+      default: null,
+      label: t('Series'),
+    },
+    entity: {
+      default: null,
+      label: t('Entity'),
+    },
+    x: {
+      default: null,
+      label: t('X Axis'),
+    },
+    y: {
+      default: null,
+      label: t('Y Axis'),
+    },
+    size: {
+      default: null,
+      label: t('Bubble Size'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 100,
+      label: t('Row limit'),
+    },
+    order_desc: {
+      default: true,
+      label: t('Order descending'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    max_bubble_size: {
+      default: '25',
+      label: t('Max Bubble Size'),
+      renderTrigger: true,
+    },
+    opacity: {
+      default: 0.6,
+      label: t('Bubble Opacity'),
+      renderTrigger: true,
+    },
+    tooltipSizeFormat: {
+      default: 'SMART_NUMBER',
+      label: t('Bubble size number format'),
+      renderTrigger: true,
+    },
+    x_axis_label: {
+      default: '',
+      label: t('X Axis Title'),
+      renderTrigger: true,
+    },
+    y_axis_label: {
+      default: '',
+      label: t('Y Axis Title'),
+      renderTrigger: true,
+    },
+    xAxisFormat: {
+      default: 'SMART_NUMBER',
+      label: t('X Axis Format'),
+      renderTrigger: true,
+    },
+    yAxisFormat: {
+      default: 'SMART_NUMBER',
+      label: t('Y Axis Format'),
+      renderTrigger: true,
+    },
+    logXAxis: {
+      default: false,
+      label: t('Logarithmic x-axis'),
+      renderTrigger: true,
+    },
+    logYAxis: {
+      default: false,
+      label: t('Logarithmic y-axis'),
+      renderTrigger: true,
+    },
+    truncateYAxis: {
+      default: false,
+      label: t('Truncate Y Axis'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/index.ts
index e8880dac1a..3a2fea3a0d 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Bubble/index.ts
@@ -20,7 +20,7 @@ import { ChartMetadata, ChartPlugin, t } from '@superset-ui/core';
 import thumbnail from './images/thumbnail.png';
 import transformProps from './transformProps';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './BubbleControlPanelSimple';
 import example1 from './images/example1.png';
 import example2 from './images/example2.png';
 import { EchartsBubbleChartProps, EchartsBubbleFormData } from './types';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/GanttControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/GanttControlPanelSimple.tsx
new file mode 100644
index 0000000000..ba645822c9
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/GanttControlPanelSimple.tsx
@@ -0,0 +1,596 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_DOCS,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import { ColumnSelectControl } from '../controls';
+
+interface GanttControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Gantt charts.
+ */
+export const GanttControlPanel: FC<GanttControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Helper for single column selection (not array)
+  const handleSingleColumnChange = (field: string) => (val: any) => {
+    const singleValue = Array.isArray(val) ? val[0] : val;
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, singleValue);
+    } else if (onChange) {
+      onChange(field, singleValue);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Start Time */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Start Time')}
+          description={t('Column representing the start time of tasks')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.start_time ? [formValues.start_time] : []}
+            onChange={handleSingleColumnChange('start_time')}
+            options={safeColumns.filter(col => col.is_dttm)}
+            name="start_time"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select start time column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No temporal columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* End Time */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('End Time')}
+          description={t('Column representing the end time of tasks')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.end_time ? [formValues.end_time] : []}
+            onChange={handleSingleColumnChange('end_time')}
+            options={safeColumns.filter(col => col.is_dttm)}
+            name="end_time"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select end time column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No temporal columns available.')}
+          </div>
+        )}
+      </div>
+
+      {/* Y-axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Y-axis')}
+          description={t('Dimension to use on y-axis.')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.y_axis ? [formValues.y_axis] : []}
+            onChange={handleSingleColumnChange('y_axis')}
+            options={safeColumns}
+            name="y_axis"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select Y-axis column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for Y-axis.')}
+          </div>
+        )}
+      </div>
+
+      {/* Series */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Series')}
+          description={t('Columns to group by')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.series || []}
+            onChange={handleChange('series')}
+            options={safeColumns}
+            name="series"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for series.')}
+          </div>
+        )}
+      </div>
+
+      {/* Subcategories - Conditional */}
+      {formValues.series && formValues.series.length > 0 && (
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Subcategories')}
+            description={t(
+              'Divides each category into subcategories based on the values in ' +
+                'the dimension. It can be used to exclude intersections.',
+            )}
+            value={formValues.subcategories ?? false}
+            onChange={handleChange('subcategories')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      )}
+
+      {/* Tooltip Metrics */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Tooltip Metrics')}
+          description={t('Metrics to display in tooltip')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.tooltip_metrics || []}
+            onChange={handleChange('tooltip_metrics')}
+            datasource={safeDataSource}
+            name="tooltip_metrics"
+            label=""
+            multi
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Tooltip Columns */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Tooltip Columns')}
+          description={t('Additional columns to display in tooltip')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.tooltip_columns || []}
+            onChange={handleChange('tooltip_columns')}
+            options={safeColumns}
+            name="tooltip_columns"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No columns available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.tooltip_metrics || []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Row limit')}
+          description={t('Limit the number of rows that are returned')}
+          hovered
+        />
+        <TextControl
+          value={formValues.row_limit}
+          onChange={handleChange('row_limit')}
+          isInt
+          placeholder="10000"
+          controlId="row_limit"
+        />
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Show Legend */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Zoomable */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Zoomable')}
+            description={t('Whether to enable zoom and pan in the chart')}
+            value={formValues.zoomable ?? true}
+            onChange={handleChange('zoomable')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show extra controls */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Extra Controls')}
+            description={t('Whether to show extra controls')}
+            value={formValues.show_extra_controls ?? false}
+            onChange={handleChange('show_extra_controls')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* X Axis Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('X Axis')}</h4>
+
+        {/* X Axis Time Bounds */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Bounds')}
+            description={t(
+              'Bounds for the X-axis. Selected time merges with ' +
+                'min/max date of the data. When left empty, bounds ' +
+                'dynamically defined based on the min/max of the data.',
+            )}
+            renderTrigger
+            hovered
+          />
+          <TextControl
+            value={formValues.x_axis_time_bounds || ''}
+            onChange={handleChange('x_axis_time_bounds')}
+            placeholder="Time range"
+            controlId="x_axis_time_bounds"
+          />
+        </div>
+
+        {/* X Axis Time Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Time format')}
+            description={D3_TIME_FORMAT_DOCS}
+            value={formValues.x_axis_time_format || 'smart_date'}
+            onChange={handleChange('x_axis_time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Tooltip Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Tooltip')}</h4>
+
+        {/* Tooltip Time Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Tooltip time format')}
+            description={D3_TIME_FORMAT_DOCS}
+            value={formValues.tooltip_time_format || 'smart_date'}
+            onChange={handleChange('tooltip_time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Tooltip Values Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Tooltip values format')}
+            description={t('Format for tooltip values')}
+            value={formValues.tooltip_values_format || 'SMART_NUMBER'}
+            onChange={handleChange('tooltip_values_format')}
+            choices={[
+              ['SMART_NUMBER', 'SMART_NUMBER'],
+              ['.1f', '.1f'],
+              ['.2f', '.2f'],
+              ['.3f', '.3f'],
+            ]}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Gantt Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualize project schedules and task timelines')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(GanttControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[GanttControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    start_time: {
+      default: null,
+      label: t('Start Time'),
+    },
+    end_time: {
+      default: null,
+      label: t('End Time'),
+    },
+    y_axis: {
+      default: null,
+      label: t('Y-axis'),
+    },
+    series: {
+      default: [],
+      label: t('Series'),
+    },
+    subcategories: {
+      default: false,
+      label: t('Subcategories'),
+      renderTrigger: true,
+    },
+    tooltip_metrics: {
+      default: [],
+      label: t('Tooltip Metrics'),
+    },
+    tooltip_columns: {
+      default: [],
+      label: t('Tooltip Columns'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 10000,
+      label: t('Row limit'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    zoomable: {
+      default: true,
+      label: t('Zoomable'),
+      renderTrigger: true,
+    },
+    show_extra_controls: {
+      default: false,
+      label: t('Extra Controls'),
+      renderTrigger: true,
+    },
+    x_axis_time_bounds: {
+      default: '',
+      label: t('Bounds'),
+      renderTrigger: true,
+    },
+    x_axis_time_format: {
+      default: 'smart_date',
+      label: t('Time format'),
+      renderTrigger: true,
+    },
+    tooltip_time_format: {
+      default: 'smart_date',
+      label: t('Tooltip time format'),
+      renderTrigger: true,
+    },
+    tooltip_values_format: {
+      default: 'SMART_NUMBER',
+      label: t('Tooltip values format'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/index.ts
index a474ceb35c..5ce14fffab 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gantt/index.ts
@@ -18,7 +18,7 @@
  */
 import { Behavior, t } from '@superset-ui/core';
 import transformProps from './transformProps';
-import controlPanel from './controlPanel';
+import controlPanel from './GanttControlPanelSimple';
 import buildQuery from './buildQuery';
 import { EchartsChartPlugin } from '../types';
 import thumbnail from './images/thumbnail.png';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/GaugeControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/GaugeControlPanelSimple.tsx
new file mode 100644
index 0000000000..baaad2d21c
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/GaugeControlPanelSimple.tsx
@@ -0,0 +1,665 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../src/explore/components/controls/SliderControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../src/explore/components/controls/CurrencyControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import { DEFAULT_FORM_DATA } from './types';
+
+interface GaugeControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Gauge charts.
+ */
+export const GaugeControlPanel: FC<GaugeControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Group by */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Columns to group by')}
+          description={t('Columns to group by')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
+            options={safeColumns}
+            name="groupby"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit and Sort by metric */}
+      <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limit the number of rows that are returned')}
+            hovered
+          />
+          <SelectControl
+            value={formValues.row_limit || DEFAULT_FORM_DATA.rowLimit}
+            onChange={handleChange('row_limit')}
+            choices={[...Array(10).keys()].map(n => [n + 1, n + 1])}
+            clearable={false}
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Sort by metric')}
+            description={t('Sort by metric in descending order')}
+            hovered
+          />
+          <CheckboxControl
+            label=""
+            description=""
+            value={formValues.sort_by_metric ?? true}
+            onChange={handleChange('sort_by_metric')}
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* General Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('General')}</h4>
+
+        {/* Min and Max Values */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Min')}
+              description={t('Minimum value on the gauge axis')}
+              hovered
+            />
+            <TextControl
+              value={formValues.min_val ?? DEFAULT_FORM_DATA.minVal}
+              onChange={handleChange('min_val')}
+              isInt
+              placeholder="0"
+              controlId="min_val"
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Max')}
+              description={t('Maximum value on the gauge axis')}
+              hovered
+            />
+            <TextControl
+              value={formValues.max_val ?? DEFAULT_FORM_DATA.maxVal}
+              onChange={handleChange('max_val')}
+              isInt
+              placeholder="100"
+              controlId="max_val"
+            />
+          </div>
+        </div>
+
+        {/* Start and End Angles */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Start angle')}
+              description={t('Angle at which to start progress axis')}
+              hovered
+            />
+            <TextControl
+              value={formValues.start_angle ?? DEFAULT_FORM_DATA.startAngle}
+              onChange={handleChange('start_angle')}
+              placeholder="225"
+              controlId="start_angle"
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('End angle')}
+              description={t('Angle at which to end progress axis')}
+              hovered
+            />
+            <TextControl
+              value={formValues.end_angle ?? DEFAULT_FORM_DATA.endAngle}
+              onChange={handleChange('end_angle')}
+              placeholder="-45"
+              controlId="end_angle"
+            />
+          </div>
+        </div>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Font Size */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Font size')}
+            description={t('Font size for axis labels, detail value and other text elements')}
+            renderTrigger
+            hovered
+          />
+          <SliderControl
+            value={formValues.font_size ?? DEFAULT_FORM_DATA.fontSize}
+            onChange={handleChange('font_size')}
+            {...{ min: 10, max: 20 }}
+          />
+        </div>
+
+        {/* Number Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Number format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.number_format || DEFAULT_FORM_DATA.numberFormat}
+            onChange={handleChange('number_format')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Currency Format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Value Format */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Value format')}
+            description={t('Additional text to add before or after the value, e.g. unit')}
+            hovered
+          />
+          <TextControl
+            value={formValues.value_formatter ?? DEFAULT_FORM_DATA.valueFormatter}
+            onChange={handleChange('value_formatter')}
+            placeholder="{value}"
+            controlId="value_formatter"
+          />
+        </div>
+
+        {/* Show Pointer and Animation */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show pointer')}
+              description={t('Whether to show the pointer')}
+              value={formValues.show_pointer ?? DEFAULT_FORM_DATA.showPointer}
+              onChange={handleChange('show_pointer')}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Animation')}
+              description={t('Whether to animate the progress and the value or just display them')}
+              value={formValues.animation ?? DEFAULT_FORM_DATA.animation}
+              onChange={handleChange('animation')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+      </div>
+
+      {/* Axis Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Axis')}</h4>
+
+        {/* Axis Options */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show axis line ticks')}
+              description={t('Whether to show minor ticks on the axis')}
+              value={formValues.show_axis_tick ?? DEFAULT_FORM_DATA.showAxisTick}
+              onChange={handleChange('show_axis_tick')}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show split lines')}
+              description={t('Whether to show the split lines on the axis')}
+              value={formValues.show_split_line ?? DEFAULT_FORM_DATA.showSplitLine}
+              onChange={handleChange('show_split_line')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        {/* Split Number */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Split number')}
+            description={t('Number of split segments on the axis')}
+            renderTrigger
+            hovered
+          />
+          <SliderControl
+            value={formValues.split_number ?? DEFAULT_FORM_DATA.splitNumber}
+            onChange={handleChange('split_number')}
+            {...{ min: 3, max: 30 }}
+          />
+        </div>
+      </div>
+
+      {/* Progress Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Progress')}</h4>
+
+        {/* Progress Options */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show progress')}
+              description={t('Whether to show the progress of gauge chart')}
+              value={formValues.show_progress ?? DEFAULT_FORM_DATA.showProgress}
+              onChange={handleChange('show_progress')}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Overlap')}
+              description={t('Whether the progress bar overlaps when there are multiple groups of data')}
+              value={formValues.overlap ?? DEFAULT_FORM_DATA.overlap}
+              onChange={handleChange('overlap')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        {/* Round Cap */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Round cap')}
+            description={t('Style the ends of the progress bar with a round cap')}
+            value={formValues.round_cap ?? DEFAULT_FORM_DATA.roundCap}
+            onChange={handleChange('round_cap')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Intervals Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Intervals')}</h4>
+
+        {/* Interval Bounds */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Interval bounds')}
+            description={t('Comma-separated interval bounds, e.g. 2,4,5 for intervals 0-2, 2-4 and 4-5. Last number should match the value provided for MAX.')}
+            hovered
+          />
+          <TextControl
+            value={formValues.intervals ?? DEFAULT_FORM_DATA.intervals}
+            onChange={handleChange('intervals')}
+            placeholder="2,4,5"
+            controlId="intervals"
+          />
+        </div>
+
+        {/* Interval Colors */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Interval colors')}
+            description={t('Comma-separated color picks for the intervals, e.g. 1,2,4. Integers denote colors from the chosen color scheme and are 1-indexed. Length must be matching that of interval bounds.')}
+            hovered
+          />
+          <TextControl
+            value={formValues.interval_color_indices ?? DEFAULT_FORM_DATA.intervalColorIndices}
+            onChange={handleChange('interval_color_indices')}
+            placeholder="1,2,4"
+            controlId="interval_color_indices"
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Gauge Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualize metrics as gauge charts showing progress towards a goal')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(GaugeControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[GaugeControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    groupby: {
+      default: [],
+      label: t('Group by'),
+    },
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: DEFAULT_FORM_DATA.rowLimit,
+      label: t('Row limit'),
+    },
+    sort_by_metric: {
+      default: true,
+      label: t('Sort by metric'),
+    },
+    min_val: {
+      default: DEFAULT_FORM_DATA.minVal,
+      label: t('Min'),
+      renderTrigger: true,
+    },
+    max_val: {
+      default: DEFAULT_FORM_DATA.maxVal,
+      label: t('Max'),
+      renderTrigger: true,
+    },
+    start_angle: {
+      default: DEFAULT_FORM_DATA.startAngle,
+      label: t('Start angle'),
+      renderTrigger: true,
+    },
+    end_angle: {
+      default: DEFAULT_FORM_DATA.endAngle,
+      label: t('End angle'),
+      renderTrigger: true,
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    font_size: {
+      default: DEFAULT_FORM_DATA.fontSize,
+      label: t('Font size'),
+      renderTrigger: true,
+    },
+    number_format: {
+      default: DEFAULT_FORM_DATA.numberFormat,
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    value_formatter: {
+      default: DEFAULT_FORM_DATA.valueFormatter,
+      label: t('Value format'),
+      renderTrigger: true,
+    },
+    show_pointer: {
+      default: DEFAULT_FORM_DATA.showPointer,
+      label: t('Show pointer'),
+      renderTrigger: true,
+    },
+    animation: {
+      default: DEFAULT_FORM_DATA.animation,
+      label: t('Animation'),
+      renderTrigger: true,
+    },
+    show_axis_tick: {
+      default: DEFAULT_FORM_DATA.showAxisTick,
+      label: t('Show axis line ticks'),
+      renderTrigger: true,
+    },
+    show_split_line: {
+      default: DEFAULT_FORM_DATA.showSplitLine,
+      label: t('Show split lines'),
+      renderTrigger: true,
+    },
+    split_number: {
+      default: DEFAULT_FORM_DATA.splitNumber,
+      label: t('Split number'),
+      renderTrigger: true,
+    },
+    show_progress: {
+      default: DEFAULT_FORM_DATA.showProgress,
+      label: t('Show progress'),
+      renderTrigger: true,
+    },
+    overlap: {
+      default: DEFAULT_FORM_DATA.overlap,
+      label: t('Overlap'),
+      renderTrigger: true,
+    },
+    round_cap: {
+      default: DEFAULT_FORM_DATA.roundCap,
+      label: t('Round cap'),
+      renderTrigger: true,
+    },
+    intervals: {
+      default: DEFAULT_FORM_DATA.intervals,
+      label: t('Interval bounds'),
+      renderTrigger: true,
+    },
+    interval_color_indices: {
+      default: DEFAULT_FORM_DATA.intervalColorIndices,
+      label: t('Interval colors'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts
index a3359826b3..6b1dd0aa52 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/index.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { t, Behavior } from '@superset-ui/core';
-import controlPanel from './controlPanel';
+import controlPanel from './GaugeControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/example1.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/GraphControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/GraphControlPanelSimple.tsx
new file mode 100644
index 0000000000..cbcaa64634
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/GraphControlPanelSimple.tsx
@@ -0,0 +1,681 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import RadioButtonControl from '../../../../packages/superset-ui-chart-controls/src/shared-controls/components/RadioButtonControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../src/explore/components/controls/SliderControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import { DEFAULT_FORM_DATA } from './types';
+
+interface GraphControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Graph charts.
+ */
+export const GraphControlPanel: FC<GraphControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Helper for single column selection (source/target expect single values)
+  const handleSingleColumnChange = (field: string) => (val: any) => {
+    const singleValue = Array.isArray(val) ? val[0] : val;
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, singleValue);
+    } else if (onChange) {
+      onChange(field, singleValue);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Check if force layout is selected
+  const isForceLayout = formValues.layout === 'force' || (!formValues.layout && DEFAULT_FORM_DATA.layout === 'force');
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Source */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Source')}
+          description={t('Name of the source nodes')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.source ? [formValues.source] : []}
+            onChange={handleSingleColumnChange('source')}
+            options={safeColumns}
+            name="source"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select source column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Target */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Target')}
+          description={t('Name of the target nodes')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.target ? [formValues.target] : []}
+            onChange={handleSingleColumnChange('target')}
+            options={safeColumns}
+            name="target"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select target column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for target.')}
+          </div>
+        )}
+      </div>
+
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Source Category */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Source category')}
+          description={t('The category of source nodes used to assign colors. If a node is associated with more than one category, only the first will be used.')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.source_category ? [formValues.source_category] : []}
+            onChange={handleSingleColumnChange('source_category')}
+            options={safeColumns}
+            name="source_category"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select source category')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for source category.')}
+          </div>
+        )}
+      </div>
+
+      {/* Target Category */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Target category')}
+          description={t('Category of target nodes')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.target_category ? [formValues.target_category] : []}
+            onChange={handleSingleColumnChange('target_category')}
+            options={safeColumns}
+            name="target_category"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select target category')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for target category.')}
+          </div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Row limit')}
+          description={t('Limit the number of rows that are returned')}
+          hovered
+        />
+        <TextControl
+          value={formValues.row_limit}
+          onChange={handleChange('row_limit')}
+          isInt
+          placeholder="1000"
+          controlId="row_limit"
+        />
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Show Legend */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Layout Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Layout')}</h4>
+
+        {/* Graph Layout */}
+        <div style={{ marginBottom: 16 }}>
+          <RadioButtonControl
+            label={t('Graph layout')}
+            description={t('Layout type of graph')}
+            value={formValues.layout || DEFAULT_FORM_DATA.layout}
+            onChange={handleChange('layout')}
+            options={[
+              ['force', t('Force')],
+              ['circular', t('Circular')],
+            ]}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Edge Symbols */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Edge symbols')}
+            description={t('Symbol of two ends of edge line')}
+            value={formValues.edgeSymbol || DEFAULT_FORM_DATA.edgeSymbol}
+            onChange={handleChange('edgeSymbol')}
+            choices={[
+              ['none,none', t('None -> None')],
+              ['none,arrow', t('None -> Arrow')],
+              ['circle,arrow', t('Circle -> Arrow')],
+              ['circle,circle', t('Circle -> Circle')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Enable node dragging - Only for force layout */}
+        {isForceLayout && (
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Enable node dragging')}
+              description={t('Whether to enable node dragging in force layout mode.')}
+              value={formValues.draggable ?? DEFAULT_FORM_DATA.draggable}
+              onChange={handleChange('draggable')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        {/* Enable graph roaming */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Enable graph roaming')}
+            description={t('Whether to enable changing graph position and scaling.')}
+            value={formValues.roam ?? DEFAULT_FORM_DATA.roam}
+            onChange={handleChange('roam')}
+            choices={[
+              [false, t('Disabled')],
+              ['scale', t('Scale only')],
+              ['move', t('Move only')],
+              [true, t('Scale and Move')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Node select mode */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Node select mode')}
+            description={t('Allow node selections')}
+            value={formValues.selectedMode ?? DEFAULT_FORM_DATA.selectedMode}
+            onChange={handleChange('selectedMode')}
+            choices={[
+              [false, t('Disabled')],
+              ['single', t('Single')],
+              ['multiple', t('Multiple')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Label threshold */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Label threshold')}
+            description={t('Minimum value for label to be displayed on graph.')}
+            hovered
+          />
+          <TextControl
+            value={formValues.showSymbolThreshold ?? DEFAULT_FORM_DATA.showSymbolThreshold}
+            onChange={handleChange('showSymbolThreshold')}
+            isInt
+            placeholder="0"
+            controlId="showSymbolThreshold"
+          />
+        </div>
+
+        {/* Node and Edge Sizes */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Node size')}
+              description={t('Median node size, the largest node will be 4 times larger than the smallest')}
+              hovered
+            />
+            <TextControl
+              value={formValues.baseNodeSize ?? DEFAULT_FORM_DATA.baseNodeSize}
+              onChange={handleChange('baseNodeSize')}
+              isFloat
+              placeholder="20"
+              controlId="baseNodeSize"
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Edge width')}
+              description={t('Median edge width, the thickest edge will be 4 times thicker than the thinnest.')}
+              hovered
+            />
+            <TextControl
+              value={formValues.baseEdgeWidth ?? DEFAULT_FORM_DATA.baseEdgeWidth}
+              onChange={handleChange('baseEdgeWidth')}
+              isFloat
+              placeholder="3"
+              controlId="baseEdgeWidth"
+            />
+          </div>
+        </div>
+
+        {/* Force Layout Options - Only show when force layout is selected */}
+        {isForceLayout && (
+          <>
+            {/* Edge length */}
+            <div style={{ marginBottom: 16 }}>
+              <ControlHeader
+                label={t('Edge length')}
+                description={t('Edge length between nodes')}
+                renderTrigger
+                hovered
+              />
+              <SliderControl
+                value={formValues.edgeLength ?? DEFAULT_FORM_DATA.edgeLength}
+                onChange={handleChange('edgeLength')}
+                {...{ min: 100, max: 1000, step: 50 }}
+              />
+            </div>
+
+            {/* Gravity */}
+            <div style={{ marginBottom: 16 }}>
+              <ControlHeader
+                label={t('Gravity')}
+                description={t('Strength to pull the graph toward center')}
+                renderTrigger
+                hovered
+              />
+              <SliderControl
+                value={formValues.gravity ?? DEFAULT_FORM_DATA.gravity}
+                onChange={handleChange('gravity')}
+                {...{ min: 0.1, max: 1, step: 0.1 }}
+              />
+            </div>
+
+            {/* Repulsion */}
+            <div style={{ marginBottom: 16 }}>
+              <ControlHeader
+                label={t('Repulsion')}
+                description={t('Repulsion strength between nodes')}
+                renderTrigger
+                hovered
+              />
+              <SliderControl
+                value={formValues.repulsion ?? DEFAULT_FORM_DATA.repulsion}
+                onChange={handleChange('repulsion')}
+                {...{ min: 100, max: 3000, step: 50 }}
+              />
+            </div>
+
+            {/* Friction */}
+            <div style={{ marginBottom: 16 }}>
+              <ControlHeader
+                label={t('Friction')}
+                description={t('Friction between nodes')}
+                renderTrigger
+                hovered
+              />
+              <SliderControl
+                value={formValues.friction ?? DEFAULT_FORM_DATA.friction}
+                onChange={handleChange('friction')}
+                {...{ min: 0.1, max: 1, step: 0.1 }}
+              />
+            </div>
+          </>
+        )}
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Graph Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualize connections between entities in a graph structure')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(GraphControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[GraphControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    source: {
+      default: '',
+      label: t('Source'),
+    },
+    target: {
+      default: '',
+      label: t('Target'),
+    },
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    source_category: {
+      default: null,
+      label: t('Source category'),
+    },
+    target_category: {
+      default: null,
+      label: t('Target category'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 1000,
+      label: t('Row limit'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    layout: {
+      default: DEFAULT_FORM_DATA.layout,
+      label: t('Graph layout'),
+      renderTrigger: true,
+    },
+    edgeSymbol: {
+      default: DEFAULT_FORM_DATA.edgeSymbol,
+      label: t('Edge symbols'),
+      renderTrigger: true,
+    },
+    draggable: {
+      default: DEFAULT_FORM_DATA.draggable,
+      label: t('Enable node dragging'),
+      renderTrigger: true,
+    },
+    roam: {
+      default: DEFAULT_FORM_DATA.roam,
+      label: t('Enable graph roaming'),
+      renderTrigger: true,
+    },
+    selectedMode: {
+      default: DEFAULT_FORM_DATA.selectedMode,
+      label: t('Node select mode'),
+      renderTrigger: true,
+    },
+    showSymbolThreshold: {
+      default: DEFAULT_FORM_DATA.showSymbolThreshold,
+      label: t('Label threshold'),
+      renderTrigger: true,
+    },
+    baseNodeSize: {
+      default: DEFAULT_FORM_DATA.baseNodeSize,
+      label: t('Node size'),
+      renderTrigger: true,
+    },
+    baseEdgeWidth: {
+      default: DEFAULT_FORM_DATA.baseEdgeWidth,
+      label: t('Edge width'),
+      renderTrigger: true,
+    },
+    edgeLength: {
+      default: DEFAULT_FORM_DATA.edgeLength,
+      label: t('Edge length'),
+      renderTrigger: true,
+    },
+    gravity: {
+      default: DEFAULT_FORM_DATA.gravity,
+      label: t('Gravity'),
+      renderTrigger: true,
+    },
+    repulsion: {
+      default: DEFAULT_FORM_DATA.repulsion,
+      label: t('Repulsion'),
+      renderTrigger: true,
+    },
+    friction: {
+      default: DEFAULT_FORM_DATA.friction,
+      label: t('Friction'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts
index 347e61d1ef..230301121c 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Graph/index.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { Behavior, t } from '@superset-ui/core';
-import controlPanel from './controlPanel';
+import controlPanel from './GraphControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example from './images/example.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/HeatmapControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/HeatmapControlPanelSimple.tsx
new file mode 100644
index 0000000000..28a98fe035
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/HeatmapControlPanelSimple.tsx
@@ -0,0 +1,754 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  LinearColorSchemeControl,
+  formatSelectOptionsForRange,
+  D3_TIME_FORMAT_OPTIONS,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../src/explore/components/controls/SliderControl';
+import ColorPickerControl from '../../../../src/explore/components/controls/ColorPickerControl';
+import CurrencyControl from '../../../../src/explore/components/controls/CurrencyControl';
+import BoundsControl from '../../../../src/explore/components/controls/BoundsControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+
+interface HeatmapControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Heatmap charts.
+ */
+export const HeatmapControlPanel: FC<HeatmapControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Helper for single column selection
+  const handleSingleColumnChange = (field: string) => (val: any) => {
+    const singleValue = Array.isArray(val) ? val[0] : val;
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, singleValue);
+    } else if (onChange) {
+      onChange(field, singleValue);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Sort axis choices
+  const sortAxisChoices = [
+    ['alpha_asc', t('Axis ascending')],
+    ['alpha_desc', t('Axis descending')],
+    ['value_asc', t('Metric ascending')],
+    ['value_desc', t('Metric descending')],
+  ];
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* X-Axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('X-Axis')}
+          description={t('Dimension to use on x-axis.')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.x_axis ? [formValues.x_axis] : []}
+            onChange={handleSingleColumnChange('x_axis')}
+            options={safeColumns}
+            name="x_axis"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select X-axis column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Time Grain */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Time Grain')}
+          description={t('Time granularity for temporal grouping')}
+          hovered
+        />
+        <SelectControl
+          value={formValues.time_grain_sqla || null}
+          onChange={handleChange('time_grain_sqla')}
+          choices={[
+            ['PT1S', t('Second')],
+            ['PT1M', t('Minute')],
+            ['PT5M', t('5 minute')],
+            ['PT10M', t('10 minute')],
+            ['PT15M', t('15 minute')],
+            ['PT30M', t('30 minute')],
+            ['PT1H', t('Hour')],
+            ['P1D', t('Day')],
+            ['P1W', t('Week')],
+            ['P1M', t('Month')],
+            ['P3M', t('Quarter')],
+            ['P1Y', t('Year')],
+          ]}
+          clearable
+          renderTrigger
+          hovered
+        />
+      </div>
+
+      {/* Y-Axis */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Y-Axis')}
+          description={t('Dimension to use on y-axis.')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.groupby ? [formValues.groupby] : []}
+            onChange={handleSingleColumnChange('groupby')}
+            options={safeColumns}
+            name="groupby"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select Y-axis column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for Y-axis.')}
+          </div>
+        )}
+      </div>
+
+      {/* Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metric')}
+          description={t('Metric to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Row limit')}
+          description={t('Limit the number of rows that are returned')}
+          hovered
+        />
+        <TextControl
+          value={formValues.row_limit}
+          onChange={handleChange('row_limit')}
+          isInt
+          placeholder="1000"
+          controlId="row_limit"
+        />
+      </div>
+
+      {/* Sort Axes */}
+      <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <SelectControl
+            label={t('Sort X Axis')}
+            value={formValues.sort_x_axis || null}
+            onChange={handleChange('sort_x_axis')}
+            choices={sortAxisChoices}
+            clearable
+            renderTrigger={false}
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <SelectControl
+            label={t('Sort Y Axis')}
+            value={formValues.sort_y_axis || null}
+            onChange={handleChange('sort_y_axis')}
+            choices={sortAxisChoices}
+            clearable
+            renderTrigger={false}
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Normalize Across */}
+      <div style={{ marginBottom: 16 }}>
+        <SelectControl
+          label={t('Normalize Across')}
+          description={
+            <div>
+              <div>
+                {t(
+                  'Color will be shaded based the normalized (0% to 100%) value of a given cell against the other cells in the selected range: ',
+                )}
+              </div>
+              <ul>
+                <li>{t('x: values are normalized within each column')}</li>
+                <li>{t('y: values are normalized within each row')}</li>
+                <li>
+                  {t('heatmap: values are normalized across the entire heatmap')}
+                </li>
+              </ul>
+            </div>
+          }
+          value={formValues.normalize_across || 'heatmap'}
+          onChange={handleChange('normalize_across')}
+          choices={[
+            ['heatmap', t('heatmap')],
+            ['x', t('x')],
+            ['y', t('y')],
+          ]}
+          clearable={false}
+          renderTrigger={false}
+          hovered
+        />
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Legend Type */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Legend Type')}
+            value={formValues.legend_type || 'continuous'}
+            onChange={handleChange('legend_type')}
+            choices={[
+              ['continuous', t('Continuous')],
+              ['piecewise', t('Piecewise')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Linear Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const linearColorSchemeControl = LinearColorSchemeControl();
+            const { hidden, ...cleanConfig } = linearColorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="linear_color_scheme"
+                value={formValues.linear_color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('linear_color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Border Color and Width */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Border color')}
+              description={t('The color of the elements border')}
+              hovered
+            />
+            <ColorPickerControl
+              value={formValues.border_color || { r: 0, g: 0, b: 0, a: 1 }}
+              onChange={handleChange('border_color')}
+              renderTrigger
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Border width')}
+              description={t('The width of the elements border')}
+              renderTrigger
+              hovered
+            />
+            <SliderControl
+              value={formValues.border_width || 0}
+              onChange={handleChange('border_width')}
+              {...{ min: 0, max: 2, step: 0.1 }}
+            />
+          </div>
+        </div>
+
+        {/* Scale Intervals */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <SelectControl
+              label={t('XScale Interval')}
+              description={t('Number of steps to take between ticks when displaying the X scale')}
+              value={formValues.xscale_interval ?? -1}
+              onChange={handleChange('xscale_interval')}
+              choices={[[-1, t('Auto')]].concat(formatSelectOptionsForRange(1, 50))}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <SelectControl
+              label={t('YScale Interval')}
+              description={t('Number of steps to take between ticks when displaying the Y scale')}
+              value={formValues.yscale_interval ?? -1}
+              onChange={handleChange('yscale_interval')}
+              choices={[[-1, t('Auto')]].concat(formatSelectOptionsForRange(1, 50))}
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        {/* Margins */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <SelectControl
+              label={t('Left Margin')}
+              description={t('Left margin, in pixels, allowing for more room for axis labels')}
+              value={formValues.left_margin || 'auto'}
+              onChange={handleChange('left_margin')}
+              choices={[
+                ['auto', t('Auto')],
+                [50, '50'],
+                [75, '75'],
+                [100, '100'],
+                [125, '125'],
+                [150, '150'],
+                [200, '200'],
+              ]}
+              freeForm
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <SelectControl
+              label={t('Bottom Margin')}
+              description={t('Bottom margin, in pixels, allowing for more room for axis labels')}
+              value={formValues.bottom_margin || 'auto'}
+              onChange={handleChange('bottom_margin')}
+              choices={[
+                ['auto', t('Auto')],
+                [50, '50'],
+                [75, '75'],
+                [100, '100'],
+                [125, '125'],
+                [150, '150'],
+                [200, '200'],
+              ]}
+              freeForm
+              clearable={false}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        {/* Value bounds */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Value bounds')}
+            description={t('Hard value bounds applied for color coding.')}
+            renderTrigger
+            hovered
+          />
+          <BoundsControl
+            value={formValues.value_bounds || [null, null]}
+            onChange={handleChange('value_bounds')}
+          />
+        </div>
+
+        {/* Format Controls */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Value Format')}
+            value={formValues.y_axis_format || null}
+            onChange={handleChange('y_axis_format')}
+            choices={[
+              ['.1f', '.1f (12345.432 => 12345.4)'],
+              ['.2f', '.2f (12345.432 => 12345.43)'],
+              ['.3f', '.3f (12345.432 => 12345.432)'],
+              ['.1%', '.1% (0.432 => 43.2%)'],
+              ['.2%', '.2% (0.432 => 43.20%)'],
+              ['.3%', '.3% (0.432 => 43.200%)'],
+              [',.1f', ',.1f (12345.432 => 12,345.4)'],
+              [',.2f', ',.2f (12345.432 => 12,345.43)'],
+              [',.3f', ',.3f (12345.432 => 12,345.432)'],
+              ['.1s', '.1s (12345.432 => 10k)'],
+              ['.2s', '.2s (12345.432 => 12k)'],
+              ['.3s', '.3s (12345.432 => 12.3k)'],
+            ]}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Date Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('X-axis time format')}
+            value={formValues.x_axis_time_format || null}
+            onChange={handleChange('x_axis_time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Currency Format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Display Options */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Legend')}
+              description={t('Whether to display the legend (toggles)')}
+              value={formValues.show_legend ?? true}
+              onChange={handleChange('show_legend')}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show percentage')}
+              description={t('Whether to include the percentage in the tooltip')}
+              value={formValues.show_percentage ?? true}
+              onChange={handleChange('show_percentage')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Show Values')}
+              description={t('Whether to display the numerical values within the cells')}
+              value={formValues.show_values ?? false}
+              onChange={handleChange('show_values')}
+              renderTrigger
+              hovered
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <CheckboxControl
+              label={t('Normalized')}
+              description={t('Whether to apply a normal distribution based on rank on the color scale')}
+              value={formValues.normalized ?? false}
+              onChange={handleChange('normalized')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart/Viz Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Heatmap')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualize correlations and patterns across two dimensions with color intensity')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(HeatmapControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[HeatmapControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    x_axis: {
+      default: null,
+      label: t('X-Axis'),
+    },
+    time_grain_sqla: {
+      default: null,
+      label: t('Time Grain'),
+    },
+    groupby: {
+      default: null,
+      label: t('Y-Axis'),
+      multi: false,
+    },
+    metric: {
+      default: null,
+      label: t('Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 1000,
+      label: t('Row limit'),
+    },
+    sort_x_axis: {
+      default: null,
+      label: t('Sort X Axis'),
+    },
+    sort_y_axis: {
+      default: null,
+      label: t('Sort Y Axis'),
+    },
+    normalize_across: {
+      default: 'heatmap',
+      label: t('Normalize Across'),
+    },
+    legend_type: {
+      default: 'continuous',
+      label: t('Legend Type'),
+      renderTrigger: true,
+    },
+    linear_color_scheme: {
+      default: 'blue_white_yellow',
+      label: t('Linear Color Scheme'),
+      renderTrigger: true,
+    },
+    border_color: {
+      default: { r: 0, g: 0, b: 0, a: 1 },
+      label: t('Border color'),
+      renderTrigger: true,
+    },
+    border_width: {
+      default: 0,
+      label: t('Border width'),
+      renderTrigger: true,
+    },
+    xscale_interval: {
+      default: -1,
+      label: t('XScale Interval'),
+      renderTrigger: true,
+    },
+    yscale_interval: {
+      default: -1,
+      label: t('YScale Interval'),
+      renderTrigger: true,
+    },
+    left_margin: {
+      default: 'auto',
+      label: t('Left Margin'),
+      renderTrigger: true,
+    },
+    bottom_margin: {
+      default: 'auto',
+      label: t('Bottom Margin'),
+      renderTrigger: true,
+    },
+    value_bounds: {
+      default: [null, null],
+      label: t('Value bounds'),
+      renderTrigger: true,
+    },
+    y_axis_format: {
+      default: null,
+      label: t('Value Format'),
+      renderTrigger: true,
+    },
+    x_axis_time_format: {
+      default: null,
+      label: t('X-axis time format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: null,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Legend'),
+      renderTrigger: true,
+    },
+    show_percentage: {
+      default: true,
+      label: t('Show percentage'),
+      renderTrigger: true,
+    },
+    show_values: {
+      default: false,
+      label: t('Show Values'),
+      renderTrigger: true,
+    },
+    normalized: {
+      default: false,
+      label: t('Normalized'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/index.ts
index 23ae090f3e..dc2ef7f2b0 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/index.ts
@@ -23,7 +23,7 @@ import example1 from './images/example1.png';
 import example2 from './images/example2.png';
 import example3 from './images/example3.png';
 import thumbnail from './images/thumbnail.png';
-import controlPanel from './controlPanel';
+import controlPanel from './HeatmapControlPanelSimple';
 
 const metadata = new ChartMetadata({
   category: t('Correlation'),
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/HistogramControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/HistogramControlPanelSimple.tsx
new file mode 100644
index 0000000000..5e7727acfc
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/HistogramControlPanelSimple.tsx
@@ -0,0 +1,493 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import {
+  t,
+  GenericDataType,
+  validateInteger,
+  validateNonEmpty,
+} from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  formatSelectOptionsForRange,
+  columnsByType,
+  D3_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+
+interface HistogramControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Histogram charts.
+ */
+export const HistogramControlPanel: FC<HistogramControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Get numeric columns for the histogram column selection
+  const numericColumns = columnsByType(datasource, GenericDataType.Numeric);
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Column (Primary metric column) */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Column')}
+          description={t('Numeric column used to calculate the histogram.')}
+          hovered
+        />
+        {numericColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.column ? [formValues.column] : []}
+            onChange={(val: any) => {
+              const singleValue = Array.isArray(val) ? val[0] : val;
+              handleChange('column')(singleValue);
+            }}
+            options={numericColumns}
+            name="column"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Select a numeric column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t(
+              'No numeric columns available. Please select a dataset with numeric data.',
+            )}
+          </div>
+        )}
+      </div>
+
+      {/* Group by */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Group by')}
+          description={t('Columns to group by')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
+            options={safeColumns}
+            name="groupby"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={[]}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit and Bins */}
+      <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limit the number of rows that are returned')}
+            hovered
+          />
+          <TextControl
+            value={formValues.row_limit}
+            onChange={handleChange('row_limit')}
+            isInt
+            placeholder="100"
+            controlId="row_limit"
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Bins')}
+            description={t('The number of bins for the histogram')}
+            hovered
+          />
+          <SelectControl
+            value={formValues.bins || 5}
+            onChange={handleChange('bins')}
+            choices={formatSelectOptionsForRange(5, 20, 5)}
+            freeForm
+            clearable={false}
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Normalize and Cumulative */}
+      <div style={{ display: 'flex', gap: 16, marginTop: 16 }}>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Normalize')}
+            description={t(`
+              The normalize option transforms the histogram values into proportions or
+              probabilities by dividing each bin's count by the total count of data points.
+              This normalization process ensures that the resulting values sum up to 1,
+              enabling a relative comparison of the data's distribution and providing a
+              clearer understanding of the proportion of data points within each bin.`)}
+            value={formValues.normalize ?? false}
+            onChange={handleChange('normalize')}
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Cumulative')}
+            description={t(`
+              The cumulative option allows you to see how your data accumulates over different
+              values. When enabled, the histogram bars represent the running total of frequencies
+              up to each bin. This helps you understand how likely it is to encounter values
+              below a certain point. Keep in mind that enabling cumulative doesn't change your
+              original data, it just changes the way the histogram is displayed.`)}
+            value={formValues.cumulative ?? false}
+            onChange={handleChange('cumulative')}
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Show Value */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Value')}
+            description={t('Show series values on the chart')}
+            value={formValues.show_value ?? false}
+            onChange={handleChange('show_value')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Show Legend */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Axis Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Axis')}</h4>
+
+        {/* X Axis Title and Format */}
+        <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader label={t('X Axis Title')} hovered />
+            <TextControl
+              value={formValues.x_axis_title || ''}
+              onChange={handleChange('x_axis_title')}
+              placeholder={t('X Axis Title')}
+              controlId="x_axis_title"
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('X Axis Format')}
+              description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+              hovered
+            />
+            <SelectControl
+              value={formValues.x_axis_format || 'SMART_NUMBER'}
+              onChange={handleChange('x_axis_format')}
+              choices={D3_FORMAT_OPTIONS}
+              freeForm
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+
+        {/* Y Axis Title and Format */}
+        <div style={{ display: 'flex', gap: 16 }}>
+          <div style={{ flex: 1 }}>
+            <ControlHeader label={t('Y Axis Title')} hovered />
+            <TextControl
+              value={formValues.y_axis_title || ''}
+              onChange={handleChange('y_axis_title')}
+              placeholder={t('Y Axis Title')}
+              controlId="y_axis_title"
+            />
+          </div>
+          <div style={{ flex: 1 }}>
+            <ControlHeader
+              label={t('Y Axis Format')}
+              description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+              hovered
+            />
+            <SelectControl
+              value={formValues.y_axis_format || 'SMART_NUMBER'}
+              onChange={handleChange('y_axis_format')}
+              choices={D3_FORMAT_OPTIONS}
+              freeForm
+              renderTrigger
+              hovered
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart Description */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Histogram')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t(
+            'Display the distribution of a dataset by representing the frequency or count of values within different ranges or bins',
+          )}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(HistogramControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[HistogramControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    column: {
+      default: null,
+      label: t('Column'),
+      validators: [validateNonEmpty],
+    },
+    groupby: {
+      default: [],
+      label: t('Group by'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 100,
+      label: t('Row limit'),
+    },
+    bins: {
+      default: 5,
+      label: t('Bins'),
+      validators: [validateInteger],
+    },
+    normalize: {
+      default: false,
+      label: t('Normalize'),
+    },
+    cumulative: {
+      default: false,
+      label: t('Cumulative'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    show_value: {
+      default: false,
+      label: t('Show Value'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    x_axis_title: {
+      default: '',
+      label: t('X Axis Title'),
+      renderTrigger: true,
+    },
+    x_axis_format: {
+      default: 'SMART_NUMBER',
+      label: t('X Axis Format'),
+      renderTrigger: true,
+    },
+    y_axis_title: {
+      default: '',
+      label: t('Y Axis Title'),
+      renderTrigger: true,
+    },
+    y_axis_format: {
+      default: 'SMART_NUMBER',
+      label: t('Y Axis Format'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/index.ts
index 15e6e84ddd..f2b4dd2a12 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Histogram/index.ts
@@ -19,7 +19,7 @@
  */
 import { ChartMetadata, ChartPlugin, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './HistogramControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/example1.png';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/MixedTimeseriesControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/MixedTimeseriesControlPanelSimple.tsx
new file mode 100644
index 0000000000..c9e0bdc460
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/MixedTimeseriesControlPanelSimple.tsx
@@ -0,0 +1,1111 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+  SORT_SERIES_CHOICES,
+  DEFAULT_SORT_SERIES_DATA,
+  CURRENCY_FORMAT_OPTIONS,
+  CurrencyFormatControl,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../src/explore/components/controls/SliderControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../src/explore/components/controls/CurrencyControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import BoundsControl from '../../../../src/explore/components/controls/BoundsControl';
+import { EchartsTimeseriesSeriesType } from '../Timeseries/types';
+
+interface MixedTimeseriesControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Mixed Timeseries charts.
+ * Supports dual Y-axes with independent formatting and chart types.
+ */
+export const MixedTimeseriesControlPanel: FC<MixedTimeseriesControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Series type choices
+  const seriesTypeChoices = [
+    [EchartsTimeseriesSeriesType.Line, t('Line')],
+    [EchartsTimeseriesSeriesType.Scatter, t('Scatter')],
+    [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')],
+    [EchartsTimeseriesSeriesType.Bar, t('Bar')],
+    [EchartsTimeseriesSeriesType.Start, t('Step - start')],
+    [EchartsTimeseriesSeriesType.Middle, t('Step - middle')],
+    [EchartsTimeseriesSeriesType.End, t('Step - end')],
+  ];
+
+  // Render query section for Query A or B
+  const renderQuerySection = (label: string, suffix: string) => (
+    <div style={{ marginBottom: 24 }}>
+      <h4>{label}</h4>
+
+      {/* Metrics */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Metrics')}
+          description={t('Metrics to display')}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues[`metrics${suffix}`] || []}
+            onChange={handleChange(`metrics${suffix}`)}
+            datasource={safeDataSource}
+            name={`metrics${suffix}`}
+            label=""
+            multi
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Group by */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Group by')}
+          description={t('Columns to group by')}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues[`groupby${suffix}`] || []}
+            onChange={handleChange(`groupby${suffix}`)}
+            options={safeColumns}
+            name={`groupby${suffix}`}
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues[`adhoc_filters${suffix}`] || []}
+            onChange={handleChange(`adhoc_filters${suffix}`)}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name={`adhoc_filters${suffix}`}
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues[`metrics${suffix}`] || []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limits and sort controls */}
+      <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Series limit')}
+            description={t('Limits the number of time series that get displayed')}
+            hovered
+          />
+          <TextControl
+            value={formValues[`limit${suffix}`]}
+            onChange={handleChange(`limit${suffix}`)}
+            isInt
+            placeholder="0"
+            controlId={`limit${suffix}`}
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Sort by metric')}
+            description={t('Metric to sort the results by')}
+            hovered
+          />
+          {safeDataSource && safeDataSource.columns ? (
+            <DndMetricSelect
+              value={formValues[`timeseries_limit_metric${suffix}`]}
+              onChange={handleChange(`timeseries_limit_metric${suffix}`)}
+              datasource={safeDataSource}
+              name={`timeseries_limit_metric${suffix}`}
+              label=""
+              multi={false}
+              savedMetrics={safeMetrics}
+            />
+          ) : (
+            <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+          )}
+        </div>
+      </div>
+
+      <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Sort Descending')}
+            description={t('Whether to sort descending or ascending')}
+            value={formValues[`order_desc${suffix}`] ?? false}
+            onChange={handleChange(`order_desc${suffix}`)}
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limit the number of rows that are returned')}
+            hovered
+          />
+          <TextControl
+            value={formValues[`row_limit${suffix}`]}
+            onChange={handleChange(`row_limit${suffix}`)}
+            isInt
+            placeholder="10000"
+            controlId={`row_limit${suffix}`}
+          />
+        </div>
+      </div>
+
+      {/* Truncate metric */}
+      <div style={{ marginBottom: 16 }}>
+        <CheckboxControl
+          label={t('Truncate Metric')}
+          description={t('Whether to truncate metric')}
+          value={formValues[`truncate_metric${suffix}`] ?? true}
+          onChange={handleChange(`truncate_metric${suffix}`)}
+          hovered
+        />
+      </div>
+    </div>
+  );
+
+  // Render customization section for Query A or B
+  const renderCustomizeSection = (label: string, suffix: string) => (
+    <div style={{ marginBottom: 24 }}>
+      <h4>{label}</h4>
+
+      {/* Series Type */}
+      <div style={{ marginBottom: 16 }}>
+        <SelectControl
+          label={t('Series type')}
+          description={t('Series chart type (line, bar etc)')}
+          value={formValues[`seriesType${suffix}`] || EchartsTimeseriesSeriesType.Line}
+          onChange={handleChange(`seriesType${suffix}`)}
+          choices={seriesTypeChoices}
+          clearable={false}
+          renderTrigger
+          hovered
+        />
+      </div>
+
+      {/* Y-Axis Assignment */}
+      <div style={{ marginBottom: 16 }}>
+        <SelectControl
+          label={t('Y Axis')}
+          description={t('Primary or secondary y-axis')}
+          value={formValues[`yAxisIndex${suffix}`] ?? 0}
+          onChange={handleChange(`yAxisIndex${suffix}`)}
+          choices={[
+            [0, t('Primary')],
+            [1, t('Secondary')],
+          ]}
+          clearable={false}
+          renderTrigger
+          hovered
+        />
+      </div>
+
+      {/* Chart Style Options */}
+      <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Stack series')}
+            description={t('Stack series on top of each other')}
+            value={formValues[`stack${suffix}`] ?? false}
+            onChange={handleChange(`stack${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Area chart')}
+            description={t('Draw area under curves. Only applicable for line types.')}
+            value={formValues[`area${suffix}`] ?? false}
+            onChange={handleChange(`area${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      <div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Show Values')}
+            description={t('Whether to display the numerical values within the cells')}
+            value={formValues[`show_value${suffix}`] ?? false}
+            onChange={handleChange(`show_value${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Marker')}
+            description={t('Draw a marker on data points. Only applicable for line types.')}
+            value={formValues[`markerEnabled${suffix}`] ?? false}
+            onChange={handleChange(`markerEnabled${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Only Total checkbox - conditional on show_value and stack */}
+      {formValues[`show_value${suffix}`] && formValues[`stack${suffix}`] && (
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Only Total')}
+            description={t('Only show the total value on the stacked chart, and not show on the selected category')}
+            value={formValues[`only_total${suffix}`] ?? true}
+            onChange={handleChange(`only_total${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+      )}
+
+      {/* Sliders for opacity and marker size */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Opacity')}
+          description={t('Opacity of area chart.')}
+          renderTrigger
+          hovered
+        />
+        <SliderControl
+          value={formValues[`opacity${suffix}`] ?? 0.7}
+          onChange={handleChange(`opacity${suffix}`)}
+          {...{ min: 0, max: 1, step: 0.1 }}
+        />
+      </div>
+
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Marker size')}
+          description={t('Size of marker. Also applies to forecast observations.')}
+          renderTrigger
+          hovered
+        />
+        <SliderControl
+          value={formValues[`markerSize${suffix}`] ?? 6}
+          onChange={handleChange(`markerSize${suffix}`)}
+          {...{ min: 0, max: 100, step: 1 }}
+        />
+      </div>
+
+      {/* Series Order */}
+      <div style={{ marginBottom: 16 }}>
+        <h5>{t('Series Order')}</h5>
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Sort Series By')}
+            description={t('Based on what should series be ordered on the chart and legend')}
+            value={formValues[`sort_series_type${suffix}`] || DEFAULT_SORT_SERIES_DATA.sort_series_type}
+            onChange={handleChange(`sort_series_type${suffix}`)}
+            choices={SORT_SERIES_CHOICES}
+            renderTrigger
+            hovered
+          />
+        </div>
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Sort Series Ascending')}
+            description={t('Sort series in ascending order')}
+            value={formValues[`sort_series_ascending${suffix}`] ?? DEFAULT_SORT_SERIES_DATA.sort_series_ascending}
+            onChange={handleChange(`sort_series_ascending${suffix}`)}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Shared query fields */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Shared query fields')}</h4>
+
+        {/* X-Axis */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('X-Axis')}
+            description={t('The column to be used as the x-axis')}
+            hovered
+          />
+          {safeColumns.length > 0 ? (
+            <DndColumnSelect
+              value={formValues.x_axis ? [formValues.x_axis] : []}
+              onChange={(val: any) => {
+                const singleValue = Array.isArray(val) ? val[0] : val;
+                handleChange('x_axis')(singleValue);
+              }}
+              options={safeColumns}
+              name="x_axis"
+              label=""
+              multi={false}
+              canDelete
+              ghostButtonText={t('Add dimension')}
+              type="DndColumnSelect"
+              actions={actions}
+            />
+          ) : (
+            <div style={{ padding: '10px' }}>
+              {t('No columns available. Please select a dataset first.')}
+            </div>
+          )}
+        </div>
+
+        {/* Time Grain */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Time Grain')}
+            description={t('The time granularity for the visualization')}
+            value={formValues.time_grain_sqla}
+            onChange={handleChange('time_grain_sqla')}
+            choices={[
+              [null, t('None')],
+              ['PT1S', t('Second')],
+              ['PT1M', t('Minute')],
+              ['PT5M', t('5 Minutes')],
+              ['PT10M', t('10 Minutes')],
+              ['PT15M', t('15 Minutes')],
+              ['PT30M', t('30 Minutes')],
+              ['PT1H', t('Hour')],
+              ['P1D', t('Day')],
+              ['P1W', t('Week')],
+              ['P1M', t('Month')],
+              ['P3M', t('Quarter')],
+              ['P1Y', t('Year')],
+            ]}
+            clearable
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Query A and Query B */}
+      {renderQuerySection(t('Query A'), '')}
+      {renderQuerySection(t('Query B'), '_b')}
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme */}
+        <div style={{ marginBottom: 16 }}>
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Zoomable */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Data Zoom')}
+            description={t('Enable data zoom controls')}
+            value={formValues.zoomable ?? true}
+            onChange={handleChange('zoomable')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Minor Ticks */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Minor ticks')}
+            description={t('Show minor ticks on axes')}
+            value={formValues.minorTicks ?? false}
+            onChange={handleChange('minorTicks')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Query A and B Customizations */}
+      {renderCustomizeSection(t('Query A'), '')}
+      {renderCustomizeSection(t('Query B'), 'B')}
+
+      {/* X-Axis Controls */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('X Axis')}</h4>
+
+        {/* X-Axis Time Format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Time format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.x_axis_time_format || 'smart_date'}
+            onChange={handleChange('x_axis_time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* X-Axis Label Rotation */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Rotate x axis label')}
+            description={t('Input field supports custom rotation')}
+            renderTrigger
+            hovered
+          />
+          <TextControl
+            value={formValues.xAxisLabelRotation ?? 0}
+            onChange={handleChange('xAxisLabelRotation')}
+            isInt
+            placeholder="0"
+            controlId="xAxisLabelRotation"
+          />
+        </div>
+      </div>
+
+      {/* Tooltip */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Tooltip')}</h4>
+
+        {/* Show query identifiers */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show query identifiers')}
+            description={t('Add Query A and Query B identifiers to tooltips to help differentiate series')}
+            value={formValues.show_query_identifiers ?? false}
+            onChange={handleChange('show_query_identifiers')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Rich tooltip */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Rich Tooltip')}
+            description={t('The rich tooltip shows a table of all series values')}
+            value={formValues.rich_tooltip ?? true}
+            onChange={handleChange('rich_tooltip')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Y-Axis Controls */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Y Axis')}</h4>
+
+        {/* Primary Y-Axis */}
+        <div style={{ marginBottom: 16 }}>
+          <h5>{t('Primary Y-Axis')}</h5>
+
+          {/* Primary Y-axis format */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Primary y-axis format')}
+              description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+              value={formValues.y_axis_format || 'SMART_NUMBER'}
+              onChange={handleChange('y_axis_format')}
+              choices={D3_FORMAT_OPTIONS}
+              freeForm
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Currency format */}
+          <div style={{ marginBottom: 16 }}>
+            <CurrencyControl
+              value={formValues.currency_format}
+              onChange={handleChange('currency_format')}
+            />
+          </div>
+
+          {/* Logarithmic y-axis */}
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Logarithmic y-axis')}
+              description={t('Logarithmic scale on primary y-axis')}
+              value={formValues.logAxis ?? false}
+              onChange={handleChange('logAxis')}
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Primary y-axis bounds */}
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Primary y-axis Bounds')}
+              description={t('Bounds for the primary Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data.')}
+              hovered
+            />
+            <BoundsControl
+              value={formValues.y_axis_bounds}
+              onChange={handleChange('y_axis_bounds')}
+              renderTrigger
+            />
+          </div>
+        </div>
+
+        {/* Secondary Y-Axis */}
+        <div style={{ marginBottom: 16 }}>
+          <h5>{t('Secondary Y-Axis')}</h5>
+
+          {/* Secondary Y-axis format */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Secondary y-axis format')}
+              description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+              value={formValues.y_axis_format_secondary}
+              onChange={handleChange('y_axis_format_secondary')}
+              choices={D3_FORMAT_OPTIONS}
+              freeForm
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Secondary currency format */}
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Secondary currency format')}
+              description={t('The currency symbol')}
+              value={formValues.currency_format_secondary}
+              onChange={handleChange('currency_format_secondary')}
+              choices={CURRENCY_FORMAT_OPTIONS}
+              freeForm
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Secondary Y-axis title */}
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Secondary y-axis title')}
+              description={t('Logarithmic y-axis')}
+              hovered
+            />
+            <TextControl
+              value={formValues.yAxisTitleSecondary || ''}
+              onChange={handleChange('yAxisTitleSecondary')}
+              placeholder=""
+              controlId="yAxisTitleSecondary"
+            />
+          </div>
+
+          {/* Logarithmic secondary y-axis */}
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Logarithmic y-axis')}
+              description={t('Logarithmic scale on secondary y-axis')}
+              value={formValues.logAxisSecondary ?? false}
+              onChange={handleChange('logAxisSecondary')}
+              renderTrigger
+              hovered
+            />
+          </div>
+
+          {/* Secondary y-axis bounds */}
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Secondary y-axis Bounds')}
+              description={t('Bounds for the secondary Y-axis. Only works when Independent Y-axis bounds are enabled.')}
+              hovered
+            />
+            <BoundsControl
+              value={formValues.y_axis_bounds_secondary}
+              onChange={handleChange('y_axis_bounds_secondary')}
+              renderTrigger
+            />
+          </div>
+        </div>
+
+        {/* Additional Y-Axis Controls */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Minor Split Line')}
+            description={t('Draw split lines for minor y-axis ticks')}
+            value={formValues.minorSplitLine ?? false}
+            onChange={handleChange('minorSplitLine')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Truncate Y Axis')}
+            description={t('Truncate Y Axis. Can be overridden by specifying a min or max bound.')}
+            value={formValues.truncateYAxis ?? true}
+            onChange={handleChange('truncateYAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart Type Picker */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Mixed Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t('Visualize two different series using the same x-axis. Note that both series can be visualized with a different chart type (e.g. 1 using bars and 1 using a line).')}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(MixedTimeseriesControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[MixedTimeseriesControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    // Shared controls
+    x_axis: {
+      default: null,
+      label: t('X-Axis'),
+    },
+    time_grain_sqla: {
+      default: null,
+      label: t('Time Grain'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    zoomable: {
+      default: true,
+      label: t('Data Zoom'),
+      renderTrigger: true,
+    },
+    minorTicks: {
+      default: false,
+      label: t('Minor ticks'),
+      renderTrigger: true,
+    },
+
+    // Query A controls
+    metrics: {
+      default: [],
+      label: t('Metrics'),
+    },
+    groupby: {
+      default: [],
+      label: t('Group by'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    limit: {
+      default: 0,
+      label: t('Series limit'),
+    },
+    timeseries_limit_metric: {
+      default: null,
+      label: t('Sort by metric'),
+    },
+    order_desc: {
+      default: false,
+      label: t('Sort Descending'),
+    },
+    row_limit: {
+      default: 10000,
+      label: t('Row limit'),
+    },
+    truncate_metric: {
+      default: true,
+      label: t('Truncate Metric'),
+    },
+    seriesType: {
+      default: EchartsTimeseriesSeriesType.Line,
+      label: t('Series type'),
+      renderTrigger: true,
+    },
+    yAxisIndex: {
+      default: 0,
+      label: t('Y Axis'),
+      renderTrigger: true,
+    },
+    stack: {
+      default: false,
+      label: t('Stack series'),
+      renderTrigger: true,
+    },
+    area: {
+      default: false,
+      label: t('Area chart'),
+      renderTrigger: true,
+    },
+    show_value: {
+      default: false,
+      label: t('Show Values'),
+      renderTrigger: true,
+    },
+    markerEnabled: {
+      default: false,
+      label: t('Marker'),
+      renderTrigger: true,
+    },
+    only_total: {
+      default: true,
+      label: t('Only Total'),
+      renderTrigger: true,
+    },
+    opacity: {
+      default: 0.7,
+      label: t('Opacity'),
+      renderTrigger: true,
+    },
+    markerSize: {
+      default: 6,
+      label: t('Marker size'),
+      renderTrigger: true,
+    },
+    sort_series_type: {
+      default: DEFAULT_SORT_SERIES_DATA.sort_series_type,
+      label: t('Sort Series By'),
+      renderTrigger: true,
+    },
+    sort_series_ascending: {
+      default: DEFAULT_SORT_SERIES_DATA.sort_series_ascending,
+      label: t('Sort Series Ascending'),
+      renderTrigger: true,
+    },
+
+    // Query B controls
+    metrics_b: {
+      default: [],
+      label: t('Metrics'),
+    },
+    groupby_b: {
+      default: [],
+      label: t('Group by'),
+    },
+    adhoc_filters_b: {
+      default: [],
+      label: t('Filters'),
+    },
+    limit_b: {
+      default: 0,
+      label: t('Series limit'),
+    },
+    timeseries_limit_metric_b: {
+      default: null,
+      label: t('Sort by metric'),
+    },
+    order_desc_b: {
+      default: false,
+      label: t('Sort Descending'),
+    },
+    row_limit_b: {
+      default: 10000,
+      label: t('Row limit'),
+    },
+    truncate_metric_b: {
+      default: true,
+      label: t('Truncate Metric'),
+    },
+    seriesTypeB: {
+      default: EchartsTimeseriesSeriesType.Line,
+      label: t('Series type'),
+      renderTrigger: true,
+    },
+    yAxisIndexB: {
+      default: 0,
+      label: t('Y Axis'),
+      renderTrigger: true,
+    },
+    stackB: {
+      default: false,
+      label: t('Stack series'),
+      renderTrigger: true,
+    },
+    areaB: {
+      default: false,
+      label: t('Area chart'),
+      renderTrigger: true,
+    },
+    show_valueB: {
+      default: false,
+      label: t('Show Values'),
+      renderTrigger: true,
+    },
+    markerEnabledB: {
+      default: false,
+      label: t('Marker'),
+      renderTrigger: true,
+    },
+    only_totalB: {
+      default: true,
+      label: t('Only Total'),
+      renderTrigger: true,
+    },
+    opacityB: {
+      default: 0.7,
+      label: t('Opacity'),
+      renderTrigger: true,
+    },
+    markerSizeB: {
+      default: 6,
+      label: t('Marker size'),
+      renderTrigger: true,
+    },
+    sort_series_typeB: {
+      default: DEFAULT_SORT_SERIES_DATA.sort_series_type,
+      label: t('Sort Series By'),
+      renderTrigger: true,
+    },
+    sort_series_ascendingB: {
+      default: DEFAULT_SORT_SERIES_DATA.sort_series_ascending,
+      label: t('Sort Series Ascending'),
+      renderTrigger: true,
+    },
+
+    // X-Axis controls
+    x_axis_time_format: {
+      default: 'smart_date',
+      label: t('Time format'),
+      renderTrigger: true,
+    },
+    xAxisLabelRotation: {
+      default: 0,
+      label: t('Rotate x axis label'),
+      renderTrigger: true,
+    },
+
+    // Tooltip controls
+    show_query_identifiers: {
+      default: false,
+      label: t('Show query identifiers'),
+      renderTrigger: true,
+    },
+    rich_tooltip: {
+      default: true,
+      label: t('Rich Tooltip'),
+      renderTrigger: true,
+    },
+
+    // Y-Axis controls
+    y_axis_format: {
+      default: 'SMART_NUMBER',
+      label: t('Primary y-axis format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    logAxis: {
+      default: false,
+      label: t('Logarithmic y-axis'),
+      renderTrigger: true,
+    },
+    y_axis_bounds: {
+      default: [null, null],
+      label: t('Primary y-axis Bounds'),
+      renderTrigger: true,
+    },
+    y_axis_format_secondary: {
+      default: undefined,
+      label: t('Secondary y-axis format'),
+      renderTrigger: true,
+    },
+    currency_format_secondary: {
+      default: undefined,
+      label: t('Secondary currency format'),
+      renderTrigger: true,
+    },
+    yAxisTitleSecondary: {
+      default: '',
+      label: t('Secondary y-axis title'),
+      renderTrigger: true,
+    },
+    logAxisSecondary: {
+      default: false,
+      label: t('Logarithmic y-axis'),
+      renderTrigger: true,
+    },
+    y_axis_bounds_secondary: {
+      default: [null, null],
+      label: t('Secondary y-axis Bounds'),
+      renderTrigger: true,
+    },
+    minorSplitLine: {
+      default: false,
+      label: t('Minor Split Line'),
+      renderTrigger: true,
+    },
+    truncateYAxis: {
+      default: true,
+      label: t('Truncate Y Axis'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts
index 5d8eee2e57..92bef71b8e 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/index.ts
@@ -18,7 +18,7 @@
  */
 import { AnnotationType, Behavior, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './MixedTimeseriesControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example from './images/example.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/RadarControlPanelSimple.tsx
similarity index 50%
copy from superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
copy to superset-frontend/plugins/plugin-chart-echarts/src/Radar/RadarControlPanelSimple.tsx
index 1372757963..ca538ad444 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/RadarControlPanelSimple.tsx
@@ -17,22 +17,26 @@
  * under the License.
  */
 import { FC, useState } from 'react';
-import { t, validateNonEmpty } from '@superset-ui/core';
+import { t } from '@superset-ui/core';
 import { Tabs } from 'antd';
 import {
   ColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
 } from '@superset-ui/chart-controls';
-
-// Direct component imports
 import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
 import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
 import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
 import TextControl from '../../../../src/explore/components/controls/TextControl';
 import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
 import ControlHeader from '../../../../src/explore/components/ControlHeader';
 import Control from '../../../../src/explore/components/Control';
+import { LABEL_POSITION } from '../constants';
 
-interface SankeyControlPanelProps {
+interface RadarControlPanelProps {
   onChange?: (field: string, value: any) => void;
   value?: Record<string, any>;
   datasource?: any;
@@ -42,9 +46,9 @@ interface SankeyControlPanelProps {
 }
 
 /**
- * A modern React component-based control panel for Sankey charts.
+ * A modern React component-based control panel for Radar charts.
  */
-export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
+export const RadarControlPanel: FC<RadarControlPanelProps> = ({
   onChange,
   value,
   datasource,
@@ -89,27 +93,23 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
   // Data tab content
   const dataTabContent = (
     <div>
-      {/* Source Column */}
+      {/* Group by */}
       <div style={{ marginBottom: 16 }}>
         <ControlHeader
-          label={t('Source')}
-          description={t('The column to be used as the source of the edge.')}
+          label={t('Group by')}
+          description={t('Columns to group by')}
           hovered
         />
         {safeColumns.length > 0 ? (
           <DndColumnSelect
-            value={formValues.source ? [formValues.source] : []}
-            onChange={(val: any) => {
-              // Source is single select, so take first value
-              const sourceValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
-              handleChange('source')(sourceValue);
-            }}
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
             options={safeColumns}
-            name="source"
+            name="groupby"
             label=""
-            multi={false}
+            multi
             canDelete
-            ghostButtonText={t('Select source column')}
+            ghostButtonText={t('Add dimension')}
             type="DndColumnSelect"
             actions={actions}
           />
@@ -120,52 +120,21 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
         )}
       </div>
 
-      {/* Target Column */}
+      {/* Metrics */}
       <div style={{ marginBottom: 16 }}>
         <ControlHeader
-          label={t('Target')}
-          description={t('The column to be used as the target of the edge.')}
-          hovered
-        />
-        {safeColumns.length > 0 ? (
-          <DndColumnSelect
-            value={formValues.target ? [formValues.target] : []}
-            onChange={(val: any) => {
-              // Target is single select, so take first value
-              const targetValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
-              handleChange('target')(targetValue);
-            }}
-            options={safeColumns}
-            name="target"
-            label=""
-            multi={false}
-            canDelete
-            ghostButtonText={t('Select target column')}
-            type="DndColumnSelect"
-            actions={actions}
-          />
-        ) : (
-          <div style={{ padding: '10px' }}>
-            {t('No columns available. Please select a dataset first.')}
-          </div>
-        )}
-      </div>
-
-      {/* Metric */}
-      <div style={{ marginBottom: 16 }}>
-        <ControlHeader
-          label={t('Metric')}
-          description={t('Metric to display')}
+          label={t('Metrics')}
+          description={t('Metrics to display')}
           hovered
         />
         {safeDataSource && safeDataSource.columns ? (
           <DndMetricSelect
-            value={formValues.metric}
-            onChange={handleChange('metric')}
+            value={formValues.metrics || []}
+            onChange={handleChange('metrics')}
             datasource={safeDataSource}
-            name="metric"
+            name="metrics"
             label=""
-            multi={false}
+            multi={true}
             savedMetrics={safeMetrics}
           />
         ) : (
@@ -189,7 +158,7 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             formData={formValues}
             name="adhoc_filters"
             savedMetrics={safeMetrics}
-            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            selectedMetrics={formValues.metrics || []}
             type="DndFilterSelect"
             actions={actions}
           />
@@ -200,33 +169,20 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
         )}
       </div>
 
-      {/* Row limit and Sort by metric */}
-      <div style={{ display: 'flex', gap: 16 }}>
-        <div style={{ flex: 1 }}>
-          <ControlHeader
-            label={t('Row limit')}
-            description={t('Limit the number of rows that are returned')}
-            hovered
-          />
-          <TextControl
-            value={formValues.row_limit}
-            onChange={handleChange('row_limit')}
-            isInt
-            placeholder="100"
-            controlId="row_limit"
-          />
-        </div>
-        <div style={{ flex: 1 }}>
-          <CheckboxControl
-            label={t('Sort by metric')}
-            description={t(
-              'Whether to sort results by the selected metric in descending order',
-            )}
-            value={formValues.sort_by_metric ?? true}
-            onChange={handleChange('sort_by_metric')}
-            hovered
-          />
-        </div>
+      {/* Row limit */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Row limit')}
+          description={t('Limit the number of rows that are returned')}
+          hovered
+        />
+        <TextControl
+          value={formValues.row_limit || 10}
+          onChange={handleChange('row_limit')}
+          isInt
+          placeholder="10"
+          controlId="row_limit"
+        />
       </div>
     </div>
   );
@@ -259,6 +215,141 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             );
           })()}
         </div>
+
+        {/* Show Legend checkbox */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Circle radar shape */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Circle radar shape')}
+            description={t("Radar render type, whether to display 'circle' shape.")}
+            value={formValues.is_circle ?? false}
+            onChange={handleChange('is_circle')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Labels Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Labels')}</h4>
+
+        {/* Show Labels checkbox */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Labels')}
+            description={t('Whether to display the labels.')}
+            value={formValues.show_labels ?? true}
+            onChange={handleChange('show_labels')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Label Type */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Label Type')}
+            description={t('What should be shown on the label?')}
+            value={formValues.label_type || 'value'}
+            onChange={handleChange('label_type')}
+            choices={[
+              ['value', t('Value')],
+              ['key_value', t('Category and Value')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Label Position */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Label position')}
+            description={t('Position of the labels')}
+            value={formValues.label_position || 'top'}
+            onChange={handleChange('label_position')}
+            choices={LABEL_POSITION}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Number format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Number format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.number_format || 'SMART_NUMBER'}
+            onChange={handleChange('number_format')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Date format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Date format')}
+            description={D3_FORMAT_DOCS}
+            value={formValues.date_format || 'smart_date'}
+            onChange={handleChange('date_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Metrics Configuration Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Metrics Configuration')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Metric Min Value')}
+            description={t('The minimum value of metrics. It is an optional configuration. If not set, it will be the minimum value of the data')}
+            hovered
+          />
+          <TextControl
+            value={formValues.radarMetricMinValue || 0}
+            onChange={handleChange('radarMetricMinValue')}
+            isFloat
+            placeholder="auto"
+            controlId="radarMetricMinValue"
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Metric Max Value')}
+            description={t('The maximum value of metrics. It is an optional configuration')}
+            hovered
+          />
+          <TextControl
+            value={formValues.radarMetricMaxValue}
+            onChange={handleChange('radarMetricMaxValue')}
+            isFloat
+            placeholder="auto"
+            controlId="radarMetricMaxValue"
+          />
+        </div>
       </div>
     </div>
   );
@@ -282,10 +373,10 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
       {/* Chart/Viz Type Picker */}
       <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
         <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
-          {t('Sankey Chart')}
+          {t('Radar Chart')}
         </div>
         <div style={{ fontSize: '12px', opacity: 0.65 }}>
-          {t('Visualize flow data as a Sankey diagram')}
+          {t('Visualize a parallel set of metrics across multiple groups. Each group is visualized using its own line of points and each metric is represented as an edge in the chart.')}
         </div>
       </div>
 
@@ -301,7 +392,7 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
 };
 
 // Mark this component as a modern panel
-(SankeyControlPanel as any).isModernPanel = true;
+(RadarControlPanel as any).isModernPanel = true;
 
 // Create a config that wraps our React component
 const config = {
@@ -309,41 +400,76 @@ const config = {
     {
       label: null,
       expanded: true,
-      controlSetRows: [[SankeyControlPanel as any]],
+      controlSetRows: [[RadarControlPanel as any]],
     },
   ],
   controlOverrides: {
-    source: {
-      default: null,
-      label: t('Source'),
-      validators: [validateNonEmpty],
-    },
-    target: {
-      default: null,
-      label: t('Target'),
-      validators: [validateNonEmpty],
+    groupby: {
+      default: [],
+      label: t('Group by'),
     },
-    metric: {
-      default: null,
-      label: t('Metric'),
+    metrics: {
+      default: [],
+      label: t('Metrics'),
     },
     adhoc_filters: {
       default: [],
       label: t('Filters'),
     },
     row_limit: {
-      default: 100,
+      default: 10,
       label: t('Row limit'),
     },
-    sort_by_metric: {
-      default: true,
-      label: t('Sort by metric'),
-    },
     color_scheme: {
       default: 'supersetColors',
       label: t('Color scheme'),
       renderTrigger: true,
     },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    show_labels: {
+      default: true,
+      label: t('Show labels'),
+      renderTrigger: true,
+    },
+    label_type: {
+      default: 'value',
+      label: t('Label Type'),
+      renderTrigger: true,
+    },
+    label_position: {
+      default: 'top',
+      label: t('Label position'),
+      renderTrigger: true,
+    },
+    number_format: {
+      default: 'SMART_NUMBER',
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    date_format: {
+      default: 'smart_date',
+      label: t('Date format'),
+      renderTrigger: true,
+    },
+    is_circle: {
+      default: false,
+      label: t('Circle radar shape'),
+      renderTrigger: true,
+    },
+    radarMetricMinValue: {
+      default: 0,
+      label: t('Metric Min Value'),
+      renderTrigger: true,
+    },
+    radarMetricMaxValue: {
+      default: null,
+      label: t('Metric Max Value'),
+      renderTrigger: true,
+    },
   },
 };
 
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts
index cac1b9f2e8..9c101cd00c 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/index.ts
@@ -19,7 +19,7 @@
  */
 import { Behavior, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './RadarControlPanelSimple';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/example1.jpg';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
index 1372757963..54091de99a 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sankey/SankeyControlPanelSimple.tsx
@@ -19,9 +19,7 @@
 import { FC, useState } from 'react';
 import { t, validateNonEmpty } from '@superset-ui/core';
 import { Tabs } from 'antd';
-import {
-  ColorSchemeControl,
-} from '@superset-ui/chart-controls';
+import { ColorSchemeControl } from '@superset-ui/chart-controls';
 
 // Direct component imports
 import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
@@ -101,7 +99,8 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             value={formValues.source ? [formValues.source] : []}
             onChange={(val: any) => {
               // Source is single select, so take first value
-              const sourceValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
+              const sourceValue =
+                Array.isArray(val) && val.length > 0 ? val[0] : null;
               handleChange('source')(sourceValue);
             }}
             options={safeColumns}
@@ -132,7 +131,8 @@ export const SankeyControlPanel: FC<SankeyControlPanelProps> = ({
             value={formValues.target ? [formValues.target] : []}
             onChange={(val: any) => {
               // Target is single select, so take first value
-              const targetValue = Array.isArray(val) && val.length > 0 ? val[0] : null;
+              const targetValue =
+                Array.isArray(val) && val.length > 0 ? val[0] : null;
               handleChange('target')(targetValue);
             }}
             options={safeColumns}
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/SunburstControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/SunburstControlPanelSimple.tsx
new file mode 100644
index 0000000000..b87f573385
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/SunburstControlPanelSimple.tsx
@@ -0,0 +1,538 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  LinearColorSchemeControl,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+} from '@superset-ui/chart-controls';
+import { DndColumnSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../src/explore/components/controls/CheckboxControl';
+import SelectControl from '../../../../src/explore/components/controls/SelectControl';
+import CurrencyControl from '../../../../src/explore/components/controls/CurrencyControl';
+import ControlHeader from '../../../../src/explore/components/ControlHeader';
+import Control from '../../../../src/explore/components/Control';
+import { DEFAULT_FORM_DATA, EchartsSunburstLabelType } from './types';
+
+interface SunburstControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A modern React component-based control panel for Sunburst charts.
+ */
+export const SunburstControlPanel: FC<SunburstControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State for active tab - must be before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // If no valid data yet, show loading state
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure datasource has the expected structure with arrays
+  const safeColumns = Array.isArray(datasource?.columns)
+    ? datasource.columns
+    : [];
+  const safeMetrics = Array.isArray(datasource?.metrics)
+    ? datasource.metrics
+    : [];
+
+  const safeDataSource = {
+    ...datasource,
+    columns: safeColumns,
+    metrics: safeMetrics,
+  };
+
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Determine if secondary metric is used (for color scheme visibility)
+  const hasSecondaryMetric =
+    formValues.secondary_metric &&
+    formValues.secondary_metric !== formValues.metric;
+
+  // Data tab content
+  const dataTabContent = (
+    <div>
+      {/* Hierarchy (Columns) */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Hierarchy')}
+          description={t(
+            'Sets the hierarchy levels of the chart. Each level is represented by one ring with the innermost circle as the top of the hierarchy.',
+          )}
+          hovered
+        />
+        {safeColumns.length > 0 ? (
+          <DndColumnSelect
+            value={formValues.columns || []}
+            onChange={handleChange('columns')}
+            options={safeColumns}
+            name="columns"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add hierarchy level')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available. Please select a dataset first.')}
+          </div>
+        )}
+      </div>
+
+      {/* Primary Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Primary Metric')}
+          description={t(
+            'The primary metric is used to define the arc segment sizes',
+          )}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.metric}
+            onChange={handleChange('metric')}
+            datasource={safeDataSource}
+            name="metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Secondary Metric */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Secondary Metric')}
+          description={t(
+            '[optional] this secondary metric is used to define the color as a ratio against the primary metric. When omitted, the color is categorical and based on labels',
+          )}
+          hovered
+        />
+        {safeDataSource && safeDataSource.columns ? (
+          <DndMetricSelect
+            value={formValues.secondary_metric}
+            onChange={handleChange('secondary_metric')}
+            datasource={safeDataSource}
+            name="secondary_metric"
+            label=""
+            multi={false}
+            savedMetrics={safeMetrics}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>{t('No metrics available.')}</div>
+        )}
+      </div>
+
+      {/* Filters */}
+      <div style={{ marginBottom: 16 }}>
+        <ControlHeader
+          label={t('Filters')}
+          description={t('Filters to apply to the data')}
+          hovered
+        />
+        {safeDataSource && safeColumns.length > 0 ? (
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={safeDataSource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metric ? [formValues.metric] : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        ) : (
+          <div style={{ padding: '10px' }}>
+            {t('No columns available for filtering.')}
+          </div>
+        )}
+      </div>
+
+      {/* Row limit and Sort by metric */}
+      <div style={{ display: 'flex', gap: 16 }}>
+        <div style={{ flex: 1 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limit the number of rows that are returned')}
+            hovered
+          />
+          <TextControl
+            value={formValues.row_limit}
+            onChange={handleChange('row_limit')}
+            isInt
+            placeholder="100"
+            controlId="row_limit"
+          />
+        </div>
+        <div style={{ flex: 1 }}>
+          <CheckboxControl
+            label={t('Sort by metric')}
+            description={t(
+              'Whether to sort results by the selected metric in descending order',
+            )}
+            value={formValues.sort_by_metric ?? true}
+            onChange={handleChange('sort_by_metric')}
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Customize tab content
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        {/* Color Scheme - Categorical (when no secondary metric) */}
+        {!hasSecondaryMetric && (
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Color scheme')}
+              description={t(
+                'When only a primary metric is provided, a categorical color scale is used.',
+              )}
+              hovered
+            />
+            {(() => {
+              const colorSchemeControl = ColorSchemeControl();
+              const { hidden, ...cleanConfig } =
+                colorSchemeControl.config || {};
+              return (
+                <Control
+                  {...cleanConfig}
+                  name="color_scheme"
+                  value={formValues.color_scheme}
+                  actions={{
+                    ...actions,
+                    setControlValue: (field: string, val: any) => {
+                      handleChange('color_scheme')(val);
+                    },
+                  }}
+                  renderTrigger
+                />
+              );
+            })()}
+          </div>
+        )}
+
+        {/* Linear Color Scheme - For secondary metric */}
+        {hasSecondaryMetric && (
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Linear color scheme')}
+              description={t(
+                'When a secondary metric is provided, a linear color scale is used.',
+              )}
+              hovered
+            />
+            {(() => {
+              const linearColorSchemeControl = LinearColorSchemeControl();
+              const { hidden, ...cleanConfig } =
+                linearColorSchemeControl.config || {};
+              return (
+                <Control
+                  {...cleanConfig}
+                  name="linear_color_scheme"
+                  value={formValues.linear_color_scheme}
+                  actions={{
+                    ...actions,
+                    setControlValue: (field: string, val: any) => {
+                      handleChange('linear_color_scheme')(val);
+                    },
+                  }}
+                  renderTrigger
+                />
+              );
+            })()}
+          </div>
+        )}
+      </div>
+
+      {/* Labels Section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Labels')}</h4>
+
+        {/* Show Labels */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Labels')}
+            description={t('Whether to display the labels.')}
+            value={formValues.show_labels ?? DEFAULT_FORM_DATA.showLabels}
+            onChange={handleChange('show_labels')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Percentage threshold */}
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Percentage threshold')}
+            description={t(
+              'Minimum threshold in percentage points for showing labels.',
+            )}
+            renderTrigger
+            hovered
+          />
+          <TextControl
+            value={formValues.show_labels_threshold ?? 5}
+            onChange={handleChange('show_labels_threshold')}
+            isFloat
+            placeholder="5"
+            controlId="show_labels_threshold"
+          />
+        </div>
+
+        {/* Show Total */}
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Total')}
+            description={t('Whether to display the aggregate count')}
+            value={formValues.show_total ?? false}
+            onChange={handleChange('show_total')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Label Type */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Label Type')}
+            description={t('What should be shown on the label?')}
+            value={formValues.label_type || DEFAULT_FORM_DATA.labelType}
+            onChange={handleChange('label_type')}
+            choices={[
+              [EchartsSunburstLabelType.Key, t('Category Name')],
+              [EchartsSunburstLabelType.Value, t('Value')],
+              [EchartsSunburstLabelType.KeyValue, t('Category and Value')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Number format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Number format')}
+            description={`${D3_FORMAT_DOCS} ${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
+            value={formValues.number_format || DEFAULT_FORM_DATA.numberFormat}
+            onChange={handleChange('number_format')}
+            choices={D3_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {/* Currency format */}
+        <div style={{ marginBottom: 16 }}>
+          <CurrencyControl
+            value={formValues.currency_format}
+            onChange={handleChange('currency_format')}
+          />
+        </div>
+
+        {/* Date format */}
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Date format')}
+            description={D3_FORMAT_DOCS}
+            value={formValues.date_format || DEFAULT_FORM_DATA.dateFormat}
+            onChange={handleChange('date_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            freeForm
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  // Tab items
+  const tabItems = [
+    {
+      key: 'data',
+      label: t('Data'),
+      children: dataTabContent,
+    },
+    {
+      key: 'customize',
+      label: t('Customize'),
+      children: customizeTabContent,
+    },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      {/* Chart Description */}
+      <div style={{ marginBottom: 16, padding: '12px', borderRadius: '4px' }}>
+        <div style={{ fontSize: '16px', fontWeight: 500, marginBottom: '8px' }}>
+          {t('Sunburst Chart')}
+        </div>
+        <div style={{ fontSize: '12px', opacity: 0.65 }}>
+          {t(
+            'Visualize flow between different entities using circles to represent different stages of a system',
+          )}
+        </div>
+      </div>
+
+      {/* Tabs for Data and Customize */}
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// Mark this component as a modern panel
+(SunburstControlPanel as any).isModernPanel = true;
+
+// Create a config that wraps our React component
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[SunburstControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    columns: {
+      default: [],
+      label: t('Hierarchy'),
+    },
+    metric: {
+      default: null,
+      label: t('Primary Metric'),
+    },
+    secondary_metric: {
+      default: null,
+      label: t('Secondary Metric'),
+    },
+    adhoc_filters: {
+      default: [],
+      label: t('Filters'),
+    },
+    row_limit: {
+      default: 100,
+      label: t('Row limit'),
+    },
+    sort_by_metric: {
+      default: true,
+      label: t('Sort by metric'),
+    },
+    color_scheme: {
+      default: 'supersetColors',
+      label: t('Color scheme'),
+      renderTrigger: true,
+    },
+    linear_color_scheme: {
+      default: 'blue_white_yellow',
+      label: t('Linear color scheme'),
+      renderTrigger: true,
+    },
+    show_labels: {
+      default: DEFAULT_FORM_DATA.showLabels,
+      label: t('Show labels'),
+      renderTrigger: true,
+    },
+    show_labels_threshold: {
+      default: 5,
+      label: t('Percentage threshold'),
+      renderTrigger: true,
+    },
+    show_total: {
+      default: false,
+      label: t('Show Total'),
+      renderTrigger: true,
+    },
+    label_type: {
+      default: DEFAULT_FORM_DATA.labelType,
+      label: t('Label Type'),
+      renderTrigger: true,
+    },
+    number_format: {
+      default: DEFAULT_FORM_DATA.numberFormat,
+      label: t('Number format'),
+      renderTrigger: true,
+    },
+    currency_format: {
+      default: undefined,
+      label: t('Currency format'),
+      renderTrigger: true,
+    },
+    date_format: {
+      default: DEFAULT_FORM_DATA.dateFormat,
+      label: t('Date format'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts
index d1715c7d81..257e7b248c 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts
@@ -19,7 +19,7 @@
 import { Behavior, t } from '@superset-ui/core';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
-import controlPanel from './controlPanel';
+import controlPanel from './SunburstControlPanelSimple';
 import buildQuery from './buildQuery';
 import example1 from './images/Sunburst1.png';
 import example2 from './images/Sunburst2.png';
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/AreaControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/AreaControlPanelSimple.tsx
new file mode 100644
index 0000000000..3577b29afe
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/AreaControlPanelSimple.tsx
@@ -0,0 +1,877 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_DOCS,
+  TimeShiftColorControl,
+  YAxisFormatControl,
+  CurrencyFormatControl,
+  ZoomableControl,
+} from '@superset-ui/chart-controls';
+
+// Direct component imports
+import { DndColumnSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../../src/explore/components/controls/SliderControl';
+import SelectControl from '../../../../../src/explore/components/controls/SelectControl';
+import ControlHeader from '../../../../../src/explore/components/ControlHeader';
+import Control from '../../../../../src/explore/components/Control';
+
+import { EchartsTimeseriesSeriesType } from '../types';
+import { TIME_SERIES_DESCRIPTION_TEXT } from '../constants';
+import { AreaChartStackControlOptions } from '../../constants';
+
+interface AreaControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+export const AreaControlPanel: FC<AreaControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State hooks must be called before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // Safety checks for datasource
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure safe data structures
+  const safeColumns = Array.isArray(datasource?.columns) ? datasource.columns : [];
+  const safeMetrics = Array.isArray(datasource?.metrics) ? datasource.metrics : [];
+
+  // Helper for control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  const dataTabContent = (
+    <div>
+      {/* Query section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Query')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('X-axis')}
+            description={t('Dimension to use on x-axis.')}
+            hovered
+          />
+          <DndColumnSelect
+            value={formValues.x_axis ? [formValues.x_axis] : []}
+            onChange={(val: any) => handleChange('x_axis')(Array.isArray(val) ? val[0] : val)}
+            options={safeColumns}
+            name="x_axis"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Time column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Metrics')}
+            description={t('One or many metrics to display')}
+            hovered
+          />
+          <DndMetricSelect
+            value={formValues.metrics || []}
+            onChange={handleChange('metrics')}
+            datasource={datasource}
+            name="metrics"
+            label=""
+            multi
+            savedMetrics={safeMetrics}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Group by')}
+            description={t('One or many columns to group by')}
+            hovered
+          />
+          <DndColumnSelect
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
+            options={safeColumns}
+            name="groupby"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Filters')}
+            description={t('Filters to apply to the chart')}
+            hovered
+          />
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={datasource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metrics ? formValues.metrics : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limits the number of rows that get displayed.')}
+            hovered
+          />
+          <TextControl
+            value={formValues.row_limit}
+            onChange={handleChange('row_limit')}
+            isInt
+            placeholder="10000"
+            controlId="row_limit"
+          />
+        </div>
+      </div>
+
+      {/* Time options */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Time Options')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time grain')}
+            description={t('The time granularity for the visualization')}
+            hovered
+          />
+          <SelectControl
+            value={formValues.time_grain_sqla}
+            onChange={handleChange('time_grain_sqla')}
+            choices={datasource?.time_grain_sqla_choices || []}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time range')}
+            description={t('The time range for the visualization')}
+            hovered
+          />
+          <TextControl
+            value={formValues.time_range}
+            onChange={handleChange('time_range')}
+            placeholder="Last week"
+            controlId="time_range"
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  const customizeTabContent = (
+    <div>
+      {/* Chart Options */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Color scheme')}
+            description={t('Color scheme for the chart')}
+            hovered
+          />
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time shift color')}
+            description={t('Color scheme for time shift comparison')}
+            hovered
+          />
+          {(() => {
+            const timeShiftColorControl = TimeShiftColorControl();
+            const { hidden, ...cleanConfig } = timeShiftColorControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="time_shift_color"
+                value={formValues.time_shift_color}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('time_shift_color')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Series Style')}
+            description={t('Series chart type (line, bar etc)')}
+            value={formValues.seriesType || EchartsTimeseriesSeriesType.Line}
+            onChange={handleChange('seriesType')}
+            choices={[
+              [EchartsTimeseriesSeriesType.Line, t('Line')],
+              [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')],
+              [EchartsTimeseriesSeriesType.Start, t('Step - start')],
+              [EchartsTimeseriesSeriesType.Middle, t('Step - middle')],
+              [EchartsTimeseriesSeriesType.End, t('Step - end')],
+            ]}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <SliderControl
+            label={t('Area chart opacity')}
+            description={t('Opacity of Area Chart. Also applies to confidence band.')}
+            value={formValues.opacity ?? 0.2}
+            onChange={handleChange('opacity')}
+            {...{ min: 0, max: 1, step: 0.1 }}
+            renderTrigger
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Value')}
+            description={t('Show series values on the chart')}
+            value={formValues.show_value ?? false}
+            onChange={handleChange('show_value')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Stacked Style')}
+            description={t('Stack series on top of each other')}
+            value={formValues.stack}
+            onChange={handleChange('stack')}
+            choices={AreaChartStackControlOptions}
+            clearable
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.show_value && formValues.stack && (
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Only Total')}
+              description={t('Only show the total value on the stacked chart, and not show on the selected category')}
+              value={formValues.only_total ?? true}
+              onChange={handleChange('only_total')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        {formValues.show_value && formValues.stack && !formValues.only_total && (
+          <div style={{ marginBottom: 16 }}>
+            <TextControl
+              label={t('Percentage threshold')}
+              description={t('Minimum threshold in percentage points for showing labels.')}
+              value={formValues.percentage_threshold}
+              onChange={handleChange('percentage_threshold')}
+              isFloat
+              controlId="percentage_threshold"
+            />
+          </div>
+        )}
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Extra Controls')}
+            description={t('Whether to show extra controls or not. Extra controls include things like making multiBar charts stacked or side by side.')}
+            value={formValues.show_extra_controls ?? false}
+            onChange={handleChange('show_extra_controls')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Marker')}
+            description={t('Draw a marker on data points. Only applicable for line types.')}
+            value={formValues.markerEnabled ?? false}
+            onChange={handleChange('markerEnabled')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.markerEnabled && (
+          <div style={{ marginBottom: 16 }}>
+            <SliderControl
+              label={t('Marker Size')}
+              description={t('Size of marker. Also applies to forecast observations.')}
+              value={formValues.markerSize ?? 6}
+              onChange={handleChange('markerSize')}
+              {...{ min: 0, max: 20, step: 1 }}
+              renderTrigger
+            />
+          </div>
+        )}
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Minor Ticks')}
+            description={t('Show minor ticks on axes')}
+            value={formValues.minorTicks ?? false}
+            onChange={handleChange('minorTicks')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Zoomable')}
+            description={t('Enable zooming')}
+            value={formValues.zoomable ?? false}
+            onChange={handleChange('zoomable')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Legend */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Legend')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.show_legend && (
+          <>
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Type')}
+                description={t('Legend type')}
+                value={formValues.legendType || 'scroll'}
+                onChange={handleChange('legendType')}
+                choices={[
+                  ['scroll', t('Scroll')],
+                  ['plain', t('Plain')],
+                ]}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Orientation')}
+                description={t('Legend Orientation')}
+                value={formValues.legendOrientation || 'top'}
+                onChange={handleChange('legendOrientation')}
+                choices={[
+                  ['top', t('Top')],
+                  ['bottom', t('Bottom')],
+                  ['left', t('Left')],
+                  ['right', t('Right')],
+                ]}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <TextControl
+                label={t('Margin')}
+                description={t('Additional padding for legend.')}
+                value={formValues.legendMargin}
+                onChange={handleChange('legendMargin')}
+                isInt
+                controlId="legendMargin"
+              />
+            </div>
+          </>
+        )}
+      </div>
+
+      {/* X Axis */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('X Axis')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Time format')}
+            description={`${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`}
+            value={formValues.x_axis_time_format || 'smart_date'}
+            onChange={handleChange('x_axis_time_format')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <SliderControl
+            label={t('Label rotation')}
+            description={t('Rotation angle for axis labels')}
+            value={formValues.xAxisLabelRotation ?? 0}
+            onChange={handleChange('xAxisLabelRotation')}
+            {...{ min: -90, max: 90, step: 15 }}
+            renderTrigger
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <TextControl
+            label={t('Label interval')}
+            description={t('Interval for axis labels')}
+            value={formValues.xAxisLabelInterval}
+            onChange={handleChange('xAxisLabelInterval')}
+            controlId="xAxisLabelInterval"
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Truncate X Axis')}
+            description={t('Truncate X Axis. Can be overridden by specifying a min or max bound.')}
+            value={formValues.truncateXAxis ?? true}
+            onChange={handleChange('truncateXAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.truncateXAxis && (
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('X Axis Bounds')}
+              description={t('Bounds for the X-axis. When left empty, the bounds are dynamically defined based on the min/max of the data.')}
+              hovered
+            />
+            <div style={{ display: 'flex', gap: 8 }}>
+              <TextControl
+                value={formValues.x_axis_bounds?.[0]}
+                onChange={(val: any) => {
+                  const bounds = formValues.x_axis_bounds || [null, null];
+                  handleChange('x_axis_bounds')([val, bounds[1]]);
+                }}
+                placeholder="Min"
+                controlId="x_axis_bounds_min"
+              />
+              <TextControl
+                value={formValues.x_axis_bounds?.[1]}
+                onChange={(val: any) => {
+                  const bounds = formValues.x_axis_bounds || [null, null];
+                  handleChange('x_axis_bounds')([bounds[0], val]);
+                }}
+                placeholder="Max"
+                controlId="x_axis_bounds_max"
+              />
+            </div>
+          </div>
+        )}
+      </div>
+
+      {/* Tooltip */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Tooltip')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Rich tooltip')}
+            description={t('Shows a list of all series available at that point in time')}
+            value={formValues.rich_tooltip ?? true}
+            onChange={handleChange('rich_tooltip')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <SelectControl
+            label={t('Tooltip time format')}
+            description={t('Time format for tooltip')}
+            value={formValues.tooltipTimeFormat || 'smart_date'}
+            onChange={handleChange('tooltipTimeFormat')}
+            choices={D3_TIME_FORMAT_OPTIONS}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show total')}
+            description={t('Display total value in tooltip')}
+            value={formValues.showTooltipTotal ?? false}
+            onChange={handleChange('showTooltipTotal')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show percentage')}
+            description={t('Show percentage in tooltip')}
+            value={formValues.showTooltipPercentage ?? false}
+            onChange={handleChange('showTooltipPercentage')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Y Axis */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Y Axis')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Y axis format')}
+            description={t('Format for Y axis values')}
+            hovered
+          />
+          {(() => {
+            const yAxisFormatControl = YAxisFormatControl();
+            const { hidden, ...cleanConfig } = yAxisFormatControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="y_axis_format"
+                value={formValues.y_axis_format}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('y_axis_format')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Currency format')}
+            description={t('Format for currency values')}
+            hovered
+          />
+          {(() => {
+            const currencyFormatControl = CurrencyFormatControl();
+            const { hidden, ...cleanConfig } = currencyFormatControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="currency_format"
+                value={formValues.currency_format}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('currency_format')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Logarithmic y-axis')}
+            description={t('Logarithmic y-axis')}
+            value={formValues.logAxis ?? false}
+            onChange={handleChange('logAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Minor Split Line')}
+            description={t('Draw split lines for minor y-axis ticks')}
+            value={formValues.minorSplitLine ?? false}
+            onChange={handleChange('minorSplitLine')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Truncate Y Axis')}
+            description={t('Truncate Y Axis. Can be overridden by specifying a min or max bound.')}
+            value={formValues.truncateYAxis ?? false}
+            onChange={handleChange('truncateYAxis')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.truncateYAxis && (
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Y Axis Bounds')}
+              description={t('Bounds for the Y-axis. When left empty, the bounds are dynamically defined based on the min/max of the data.')}
+              hovered
+            />
+            <div style={{ display: 'flex', gap: 8 }}>
+              <TextControl
+                value={formValues.y_axis_bounds?.[0]}
+                onChange={(val: any) => {
+                  const bounds = formValues.y_axis_bounds || [null, null];
+                  handleChange('y_axis_bounds')([val, bounds[1]]);
+                }}
+                placeholder="Min"
+                controlId="y_axis_bounds_min"
+              />
+              <TextControl
+                value={formValues.y_axis_bounds?.[1]}
+                onChange={(val: any) => {
+                  const bounds = formValues.y_axis_bounds || [null, null];
+                  handleChange('y_axis_bounds')([bounds[0], val]);
+                }}
+                placeholder="Max"
+                controlId="y_axis_bounds_max"
+              />
+            </div>
+          </div>
+        )}
+      </div>
+    </div>
+  );
+
+  const tabItems = [
+    { key: 'data', label: t('Data'), children: dataTabContent },
+    { key: 'customize', label: t('Customize'), children: customizeTabContent },
+  ];
+
+  return (
+    <div style={{ padding: '16px' }}>
+      <Tabs
+        activeKey={activeTab}
+        onChange={setActiveTab}
+        items={tabItems}
+        size="large"
+      />
+    </div>
+  );
+};
+
+// CRITICAL: Mark as modern panel
+(AreaControlPanel as any).isModernPanel = true;
+
+// Export wrapper config for compatibility
+const config = {
+  controlPanelSections: [
+    {
+      label: null,
+      expanded: true,
+      controlSetRows: [[AreaControlPanel as any]],
+    },
+  ],
+  controlOverrides: {
+    row_limit: {
+      default: 10000,
+      label: t('Row limit'),
+      renderTrigger: true,
+    },
+    opacity: {
+      default: 0.2,
+      label: t('Area chart opacity'),
+      renderTrigger: true,
+    },
+    seriesType: {
+      default: EchartsTimeseriesSeriesType.Line,
+      label: t('Series Style'),
+      renderTrigger: true,
+    },
+    show_value: {
+      default: false,
+      label: t('Show Value'),
+      renderTrigger: true,
+    },
+    markerEnabled: {
+      default: false,
+      label: t('Marker'),
+      renderTrigger: true,
+    },
+    markerSize: {
+      default: 6,
+      label: t('Marker Size'),
+      renderTrigger: true,
+    },
+    logAxis: {
+      default: false,
+      label: t('Logarithmic y-axis'),
+      renderTrigger: true,
+    },
+    minorSplitLine: {
+      default: false,
+      label: t('Minor Split Line'),
+      renderTrigger: true,
+    },
+    truncateXAxis: {
+      default: true,
+      label: t('Truncate X Axis'),
+      renderTrigger: true,
+    },
+    truncateYAxis: {
+      default: false,
+      label: t('Truncate Y Axis'),
+      renderTrigger: true,
+    },
+    x_axis_time_format: {
+      default: 'smart_date',
+      label: t('Time format'),
+      renderTrigger: true,
+    },
+    rich_tooltip: {
+      default: true,
+      label: t('Rich tooltip'),
+      renderTrigger: true,
+    },
+    tooltipTimeFormat: {
+      default: 'smart_date',
+      label: t('Tooltip time format'),
+      renderTrigger: true,
+    },
+    zoomable: {
+      default: false,
+      label: t('Zoomable'),
+      renderTrigger: true,
+    },
+    show_legend: {
+      default: true,
+      label: t('Show legend'),
+      renderTrigger: true,
+    },
+    legendType: {
+      default: 'scroll',
+      label: t('Legend type'),
+      renderTrigger: true,
+    },
+    legendOrientation: {
+      default: 'top',
+      label: t('Legend orientation'),
+      renderTrigger: true,
+    },
+    minorTicks: {
+      default: false,
+      label: t('Minor Ticks'),
+      renderTrigger: true,
+    },
+    show_extra_controls: {
+      default: false,
+      label: t('Extra Controls'),
+      renderTrigger: true,
+    },
+    only_total: {
+      default: true,
+      label: t('Only Total'),
+      renderTrigger: true,
+    },
+    percentage_threshold: {
+      default: 0,
+      label: t('Percentage threshold'),
+      renderTrigger: true,
+    },
+  },
+};
+
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts
index cac7237976..712f5b8db0 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Area/index.ts
@@ -18,7 +18,7 @@
  */
 import { t, AnnotationType, Behavior } from '@superset-ui/core';
 import buildQuery from '../buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from './AreaControlPanelSimple';
 import transformProps from '../transformProps';
 import thumbnail from './images/thumbnail.png';
 import {
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/BarControlPanelSimple.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/BarControlPanelSimple.tsx
new file mode 100644
index 0000000000..190ccad610
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/BarControlPanelSimple.tsx
@@ -0,0 +1,1075 @@
+/**
+ * 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.
+ */
+import { FC, useState } from 'react';
+import { t } from '@superset-ui/core';
+import { Tabs } from 'antd';
+import {
+  ColorSchemeControl,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_OPTIONS,
+  D3_TIME_FORMAT_DOCS,
+  TimeShiftColorControl,
+  YAxisFormatControl,
+  CurrencyFormatControl,
+  ZoomableControl,
+} from '@superset-ui/chart-controls';
+
+// Direct component imports
+import { DndColumnSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndColumnSelect';
+import { DndMetricSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndMetricSelect';
+import { DndFilterSelect } from '../../../../../src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
+import TextControl from '../../../../../src/explore/components/controls/TextControl';
+import CheckboxControl from '../../../../../src/explore/components/controls/CheckboxControl';
+import SliderControl from '../../../../../src/explore/components/controls/SliderControl';
+import SelectControl from '../../../../../src/explore/components/controls/SelectControl';
+import RadioButtonControl from '../../../../../src/explore/components/controls/RadioButtonControl';
+import ControlHeader from '../../../../../src/explore/components/ControlHeader';
+import Control from '../../../../../src/explore/components/Control';
+
+import { OrientationType } from '../../types';
+import { TIME_SERIES_DESCRIPTION_TEXT } from '../../constants';
+import { StackControlsValue } from '../../../constants';
+
+interface BarControlPanelProps {
+  onChange?: (field: string, value: any) => void;
+  value?: Record<string, any>;
+  datasource?: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+export const BarControlPanel: FC<BarControlPanelProps> = ({
+  onChange,
+  value,
+  datasource,
+  form_data,
+  actions,
+  controls,
+}) => {
+  // State hooks must be called before any early returns
+  const [activeTab, setActiveTab] = useState('data');
+
+  // Safety checks for datasource
+  if (!datasource || !form_data) {
+    return <div>Loading control panel...</div>;
+  }
+
+  // Ensure safe data structures
+  const safeColumns = Array.isArray(datasource?.columns) ? datasource.columns : [];
+  const safeMetrics = Array.isArray(datasource?.metrics) ? datasource.metrics : [];
+
+  // Helper for control changes
+  const handleChange = (field: string) => (val: any) => {
+    if (actions?.setControlValue) {
+      actions.setControlValue(field, val);
+    } else if (onChange) {
+      onChange(field, val);
+    }
+  };
+
+  // Get form values
+  const formValues = form_data || value || {};
+
+  // Helpers for orientation-dependent axis controls
+  const isVertical = formValues.orientation === OrientationType.Vertical;
+  const isHorizontal = formValues.orientation === OrientationType.Horizontal;
+
+  const dataTabContent = (
+    <div>
+      {/* Query section */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Query')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('X-axis')}
+            description={t('Dimension to use on x-axis.')}
+            hovered
+          />
+          <DndColumnSelect
+            value={formValues.x_axis ? [formValues.x_axis] : []}
+            onChange={(val: any) => handleChange('x_axis')(Array.isArray(val) ? val[0] : val)}
+            options={safeColumns}
+            name="x_axis"
+            label=""
+            multi={false}
+            canDelete
+            ghostButtonText={t('Time column')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Metrics')}
+            description={t('One or many metrics to display')}
+            hovered
+          />
+          <DndMetricSelect
+            value={formValues.metrics || []}
+            onChange={handleChange('metrics')}
+            datasource={datasource}
+            name="metrics"
+            label=""
+            multi
+            savedMetrics={safeMetrics}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Group by')}
+            description={t('One or many columns to group by')}
+            hovered
+          />
+          <DndColumnSelect
+            value={formValues.groupby || []}
+            onChange={handleChange('groupby')}
+            options={safeColumns}
+            name="groupby"
+            label=""
+            multi
+            canDelete
+            ghostButtonText={t('Add dimension')}
+            type="DndColumnSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Filters')}
+            description={t('Filters to apply to the chart')}
+            hovered
+          />
+          <DndFilterSelect
+            value={formValues.adhoc_filters || []}
+            onChange={handleChange('adhoc_filters')}
+            datasource={datasource}
+            columns={safeColumns}
+            formData={formValues}
+            name="adhoc_filters"
+            savedMetrics={safeMetrics}
+            selectedMetrics={formValues.metrics ? formValues.metrics : []}
+            type="DndFilterSelect"
+            actions={actions}
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Row limit')}
+            description={t('Limits the number of rows that get displayed.')}
+            hovered
+          />
+          <TextControl
+            value={formValues.row_limit}
+            onChange={handleChange('row_limit')}
+            isInt
+            placeholder="10000"
+            controlId="row_limit"
+          />
+        </div>
+      </div>
+
+      {/* Time options */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Time Options')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time grain')}
+            description={t('The time granularity for the visualization')}
+            hovered
+          />
+          <SelectControl
+            value={formValues.time_grain_sqla}
+            onChange={handleChange('time_grain_sqla')}
+            choices={datasource?.time_grain_sqla_choices || []}
+            clearable={false}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time range')}
+            description={t('The time range for the visualization')}
+            hovered
+          />
+          <TextControl
+            value={formValues.time_range}
+            onChange={handleChange('time_range')}
+            placeholder="Last week"
+            controlId="time_range"
+          />
+        </div>
+      </div>
+    </div>
+  );
+
+  const customizeTabContent = (
+    <div>
+      {/* Chart Orientation */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Orientation')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <RadioButtonControl
+            label={t('Bar orientation')}
+            description={t('Orientation of bar chart')}
+            value={formValues.orientation || OrientationType.Vertical}
+            onChange={handleChange('orientation')}
+            options={[
+              [OrientationType.Vertical, t('Vertical')],
+              [OrientationType.Horizontal, t('Horizontal')],
+            ]}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Chart Options */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Chart Options')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Color scheme')}
+            description={t('Color scheme for the chart')}
+            hovered
+          />
+          {(() => {
+            const colorSchemeControl = ColorSchemeControl();
+            const { hidden, ...cleanConfig } = colorSchemeControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="color_scheme"
+                value={formValues.color_scheme}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('color_scheme')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Time shift color')}
+            description={t('Color scheme for time shift comparison')}
+            hovered
+          />
+          {(() => {
+            const timeShiftColorControl = TimeShiftColorControl();
+            const { hidden, ...cleanConfig } = timeShiftColorControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="time_shift_color"
+                value={formValues.time_shift_color}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('time_shift_color')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show Value')}
+            description={t('Show series values on the chart')}
+            value={formValues.show_value ?? false}
+            onChange={handleChange('show_value')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.stack === StackControlsValue.Stack && (
+          <div style={{ marginBottom: 16 }}>
+            <SelectControl
+              label={t('Split stack by')}
+              description={t('Stack in groups, where each group corresponds to a dimension')}
+              value={formValues.stackDimension}
+              onChange={handleChange('stackDimension')}
+              choices={formValues.groupby ? formValues.groupby.map((val: any) => [val.toString(), val.toString()]) : []}
+              clearable
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Minor Ticks')}
+            description={t('Show minor ticks on axes')}
+            value={formValues.minorTicks ?? false}
+            onChange={handleChange('minorTicks')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Zoomable')}
+            description={t('Enable zooming')}
+            value={formValues.zoomable ?? false}
+            onChange={handleChange('zoomable')}
+            renderTrigger
+            hovered
+          />
+        </div>
+      </div>
+
+      {/* Legend */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('Legend')}</h4>
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
+            label={t('Show legend')}
+            description={t('Whether to display a legend for the chart')}
+            value={formValues.show_legend ?? true}
+            onChange={handleChange('show_legend')}
+            renderTrigger
+            hovered
+          />
+        </div>
+
+        {formValues.show_legend && (
+          <>
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Type')}
+                description={t('Legend type')}
+                value={formValues.legendType || 'scroll'}
+                onChange={handleChange('legendType')}
+                choices={[
+                  ['scroll', t('Scroll')],
+                  ['plain', t('Plain')],
+                ]}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Orientation')}
+                description={t('Legend Orientation')}
+                value={formValues.legendOrientation || 'top'}
+                onChange={handleChange('legendOrientation')}
+                choices={[
+                  ['top', t('Top')],
+                  ['bottom', t('Bottom')],
+                  ['left', t('Left')],
+                  ['right', t('Right')],
+                ]}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <TextControl
+                label={t('Margin')}
+                description={t('Additional padding for legend.')}
+                value={formValues.legendMargin}
+                onChange={handleChange('legendMargin')}
+                isInt
+                controlId="legendMargin"
+              />
+            </div>
+          </>
+        )}
+      </div>
+
+      {/* X Axis */}
+      <div style={{ marginBottom: 24 }}>
+        <h4>{t('X Axis')}</h4>
+
+        {/* X-axis title controls - show when vertical */}
+        {isVertical && (
+          <>
+            <div style={{ marginBottom: 16 }}>
+              <TextControl
+                label={t('Axis Title')}
+                description={t('Title for the X axis')}
+                value={formValues.x_axis_title}
+                onChange={handleChange('x_axis_title')}
+                controlId="x_axis_title"
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Axis Title Margin')}
+                description={t('Margin for axis title')}
+                value={formValues.x_axis_title_margin}
+                onChange={handleChange('x_axis_title_margin')}
+                choices={[
+                  [5, '5'],
+                  [10, '10'],
+                  [15, '15'],
+                  [20, '20'],
+                  [25, '25'],
+                  [30, '30'],
+                ]}
+                clearable
+                renderTrigger
+                hovered
+              />
+            </div>
+          </>
+        )}
+
+        {/* X-axis format controls - show when vertical */}
+        {isVertical && (
+          <>
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Time format')}
+                description={`${D3_TIME_FORMAT_DOCS}. ${TIME_SERIES_DESCRIPTION_TEXT}`}
+                value={formValues.x_axis_time_format || 'smart_date'}
+                onChange={handleChange('x_axis_time_format')}
+                choices={D3_TIME_FORMAT_OPTIONS}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SliderControl
+                label={t('Label rotation')}
+                description={t('Rotation angle for axis labels')}
+                value={formValues.xAxisLabelRotation ?? 0}
+                onChange={handleChange('xAxisLabelRotation')}
+                {...{ min: -90, max: 90, step: 15 }}
+                renderTrigger
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <TextControl
+                label={t('Label interval')}
+                description={t('Interval for axis labels')}
+                value={formValues.xAxisLabelInterval}
+                onChange={handleChange('xAxisLabelInterval')}
+                controlId="xAxisLabelInterval"
+              />
+            </div>
+          </>
+        )}
+
+        {/* Y-axis title controls - show when horizontal */}
+        {isHorizontal && (
+          <>
+            <div style={{ marginBottom: 16 }}>
+              <TextControl
+                label={t('Axis Title')}
+                description={t('Title for the Y axis')}
+                value={formValues.y_axis_title}
+                onChange={handleChange('y_axis_title')}
+                controlId="y_axis_title"
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Axis Title Margin')}
+                description={t('Margin for axis title')}
+                value={formValues.y_axis_title_margin}
+                onChange={handleChange('y_axis_title_margin')}
+                choices={[
+                  [5, '5'],
+                  [10, '10'],
+                  [15, '15'],
+                  [20, '20'],
+                  [25, '25'],
+                  [30, '30'],
+                ]}
+                clearable
+                renderTrigger
+                hovered
+              />
+            </div>
+
+            <div style={{ marginBottom: 16 }}>
+              <SelectControl
+                label={t('Axis Title Position')}
+                description={t('Position of the axis title')}
+                value={formValues.y_axis_title_position || 'Left'}
+                onChange={handleChange('y_axis_title_position')}
+                choices={[
+                  ['Left', t('Left')],
+                  ['Top', t('Top')],
+                ]}
+                clearable={false}
+                renderTrigger
+                hovered
+              />
+            </div>
+          </>
+        )}
+
+        {/* Y-axis format controls - show when horizontal */}
+        {isHorizontal && (
+          <div style={{ marginBottom: 16 }}>
+            <ControlHeader
+              label={t('Axis Format')}
+              description={t('Format for axis values')}
+              hovered
+            />
+            {(() => {
+              const yAxisFormatControl = YAxisFormatControl();
+              const { hidden, ...cleanConfig } = yAxisFormatControl.config || {};
+              return (
+                <Control
+                  {...cleanConfig}
+                  name="y_axis_format"
+                  value={formValues.y_axis_format}
+                  actions={{
+                    ...actions,
+                    setControlValue: (field: string, val: any) => {
+                      handleChange('y_axis_format')(val);
+                    },
+                  }}
+                  renderTrigger
+                />
+              );
+            })()}
+          </div>
+        )}
+
+        <div style={{ marginBottom: 16 }}>
+          <ControlHeader
+            label={t('Currency format')}
+            description={t('Format for currency values')}
+            hovered
+          />
+          {(() => {
+            const currencyFormatControl = CurrencyFormatControl();
+            const { hidden, ...cleanConfig } = currencyFormatControl.config || {};
+            return (
+              <Control
+                {...cleanConfig}
+                name="currency_format"
+                value={formValues.currency_format}
+                actions={{
+                  ...actions,
+                  setControlValue: (field: string, val: any) => {
+                    handleChange('currency_format')(val);
+                  },
+                }}
+                renderTrigger
+              />
+            );
+          })()}
+        </div>
+
+        {/* Logarithmic axis - show for value axis based on orientation */}
+        {((isVertical && isHorizontal) || isHorizontal) && (
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Logarithmic axis')}
+              description={t('Logarithmic axis')}
+              value={formValues.logAxis ?? false}
+              onChange={handleChange('logAxis')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        {/* Minor split line - show for value axis based on orientation */}
+        {((isVertical && isHorizontal) || isHorizontal) && (
+          <div style={{ marginBottom: 16 }}>
+            <CheckboxControl
+              label={t('Minor Split Line')}
+              description={t('Draw split lines for minor axis ticks')}
+              value={formValues.minorSplitLine ?? false}
+              onChange={handleChange('minorSplitLine')}
+              renderTrigger
+              hovered
+            />
+          </div>
+        )}
+
+        <div style={{ marginBottom: 16 }}>
+          <CheckboxControl
... 4887 lines suppressed ...