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 df772a9afa6adb9c8270dc54865aa8438d7056fa
Author: Evan Rusackas <[email protected]>
AuthorDate: Thu Aug 14 09:51:09 2025 -0700

    feat: Implement nuclear approach for control panel migration
    
    - Create empty control panel placeholder for non-migrated charts
    - Switch Bar and Line charts to empty panels temporarily
    - Update Pie chart to use traditional control config structure
    - Remove experimental React-based PieControlPanel component
    - Fix TypeScript errors in control panel configurations
    - Simplify migration path by focusing on one working chart first
    
    This approach allows us to get one chart (Pie) working properly
    before migrating others, avoiding complex dual-architecture issues.
---
 superset-frontend/package-lock.json                |   2 +-
 .../components/ModernControlPanelExample.tsx       | 282 --------
 .../components/ReactControlWrappers.tsx            | 370 ----------
 .../src/shared-controls/components/index.tsx       |   3 -
 .../src/Pie/controlPanelModern.tsx                 | 775 +++++++++------------
 .../plugins/plugin-chart-echarts/src/Pie/index.ts  |   3 +-
 .../src/Timeseries/Regular/Bar/index.ts            |   2 +-
 .../src/Timeseries/Regular/Line/index.ts           |   2 +-
 .../plugin-chart-echarts/src/emptyControlPanel.ts  |  36 +
 .../components/ModernControlPanelRenderer.tsx      |  20 +-
 10 files changed, 387 insertions(+), 1108 deletions(-)

diff --git a/superset-frontend/package-lock.json 
b/superset-frontend/package-lock.json
index ad6ac17411..5442463535 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -61644,7 +61644,7 @@
         "@storybook/types": "8.4.7",
         "@types/react-loadable": "^5.5.11",
         "core-js": "3.40.0",
-        "gh-pages": "^6.2.0",
+        "gh-pages": "^6.3.0",
         "jquery": "^3.7.1",
         "memoize-one": "^5.2.1",
         "react": "^17.0.2",
diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ModernControlPanelExample.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ModernControlPanelExample.tsx
deleted file mode 100644
index 89140363df..0000000000
--- 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ModernControlPanelExample.tsx
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
- * 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 } from 'react';
-import { t } from '@superset-ui/core';
-import { Row, Col } from '@superset-ui/core/components';
-import {
-  ControlSection,
-  SingleControlRow,
-  TwoColumnRow,
-  ThreeColumnRow,
-} from './ControlPanelLayout';
-import {
-  GroupBy,
-  Metrics,
-  AdhocFilters,
-  ColorScheme,
-} from './ReactControlWrappers';
-
-/**
- * Example of a modern control panel that uses React components directly
- * instead of the legacy controlSetRows structure.
- *
- * This demonstrates how to:
- * 1. Use Ant Design's Row/Col for layout
- * 2. Use our layout utility components
- * 3. Structure sections with React components
- * 4. Avoid the nested array structure of controlSetRows
- */
-
-interface ModernControlPanelProps {
-  values: Record<string, any>;
-  onChange: (name: string, value: any) => void;
-  datasource?: any;
-}
-
-export const ModernControlPanelExample: FC<ModernControlPanelProps> = ({
-  values,
-  onChange,
-  datasource,
-}) => (
-  <div className="modern-control-panel">
-    {/* Query Section - Always expanded */}
-    <ControlSection label={t('Query')} expanded>
-      {/* Single control in full width */}
-      <SingleControlRow>
-        <GroupBy value={values.groupby} onChange={onChange} />
-      </SingleControlRow>
-
-      {/* Two controls side by side */}
-      <TwoColumnRow
-        left={<Metrics value={values.metrics} onChange={onChange} />}
-        right={
-          <AdhocFilters value={values.adhoc_filters} onChange={onChange} />
-        }
-      />
-
-      {/* Three controls in a row */}
-      <ThreeColumnRow
-        left={
-          <div>
-            <label>{t('Row Limit')}</label>
-            <input
-              type="number"
-              value={values.row_limit || 100}
-              onChange={e =>
-                onChange('row_limit', parseInt(e.target.value, 10))
-              }
-            />
-          </div>
-        }
-        center={
-          <div>
-            <label>{t('Sort By')}</label>
-            <select
-              value={values.sort_by || 'metric'}
-              onChange={e => onChange('sort_by', e.target.value)}
-            >
-              <option value="metric">Metric</option>
-              <option value="alpha">Alphabetical</option>
-            </select>
-          </div>
-        }
-        right={
-          <div>
-            <label>{t('Order')}</label>
-            <select
-              value={values.order || 'desc'}
-              onChange={e => onChange('order', e.target.value)}
-            >
-              <option value="desc">Descending</option>
-              <option value="asc">Ascending</option>
-            </select>
-          </div>
-        }
-      />
-    </ControlSection>
-
-    {/* Appearance Section - Collapsible */}
-    <ControlSection
-      label={t('Appearance')}
-      description={t('Customize chart appearance')}
-      expanded={false}
-    >
-      {/* Using Row/Col directly for custom layouts */}
-      <Row gutter={[16, 16]}>
-        <Col span={24}>
-          <ColorScheme value={values.color_scheme} onChange={onChange} />
-        </Col>
-      </Row>
-
-      <Row gutter={[16, 16]}>
-        <Col span={8}>
-          <label>{t('Opacity')}</label>
-          <input
-            type="range"
-            min="0"
-            max="1"
-            step="0.1"
-            value={values.opacity || 1}
-            onChange={e => onChange('opacity', parseFloat(e.target.value))}
-          />
-        </Col>
-        <Col span={8}>
-          <label>{t('Show Legend')}</label>
-          <input
-            type="checkbox"
-            checked={values.show_legend ?? true}
-            onChange={e => onChange('show_legend', e.target.checked)}
-          />
-        </Col>
-        <Col span={8}>
-          <label>{t('Show Labels')}</label>
-          <input
-            type="checkbox"
-            checked={values.show_labels ?? false}
-            onChange={e => onChange('show_labels', e.target.checked)}
-          />
-        </Col>
-      </Row>
-
-      {/* Conditional controls */}
-      {values.show_labels && (
-        <Row gutter={[16, 16]}>
-          <Col span={12}>
-            <label>{t('Label Type')}</label>
-            <select
-              value={values.label_type || 'value'}
-              onChange={e => onChange('label_type', e.target.value)}
-            >
-              <option value="value">Value</option>
-              <option value="percent">Percentage</option>
-              <option value="key">Category</option>
-            </select>
-          </Col>
-          <Col span={12}>
-            <label>{t('Label Position')}</label>
-            <select
-              value={values.label_position || 'inside'}
-              onChange={e => onChange('label_position', e.target.value)}
-            >
-              <option value="inside">Inside</option>
-              <option value="outside">Outside</option>
-            </select>
-          </Col>
-        </Row>
-      )}
-    </ControlSection>
-
-    {/* Advanced Section */}
-    <ControlSection label={t('Advanced')} expanded={false}>
-      <Row gutter={[16, 16]}>
-        <Col span={24}>
-          <label>{t('Custom CSS')}</label>
-          <textarea
-            value={values.custom_css || ''}
-            onChange={e => onChange('custom_css', e.target.value)}
-            rows={4}
-            style={{ width: '100%' }}
-            placeholder={t('Enter custom CSS styles')}
-          />
-        </Col>
-      </Row>
-    </ControlSection>
-  </div>
-);
-
-/**
- * Alternative approach using a configuration object
- * This could be used to generate the UI dynamically
- */
-export const modernPanelConfig = {
-  sections: [
-    {
-      id: 'query',
-      label: t('Query'),
-      expanded: true,
-      rows: [
-        {
-          type: 'single',
-          control: { type: 'groupby', name: 'groupby' },
-        },
-        {
-          type: 'double',
-          left: { type: 'metrics', name: 'metrics' },
-          right: { type: 'adhoc_filters', name: 'adhoc_filters' },
-        },
-        {
-          type: 'triple',
-          left: { type: 'row_limit', name: 'row_limit' },
-          center: { type: 'sort_by', name: 'sort_by' },
-          right: { type: 'order', name: 'order' },
-        },
-      ],
-    },
-    {
-      id: 'appearance',
-      label: t('Appearance'),
-      description: t('Customize chart appearance'),
-      expanded: false,
-      rows: [
-        {
-          type: 'single',
-          control: { type: 'color_scheme', name: 'color_scheme' },
-        },
-        {
-          type: 'custom',
-          render: (values: any, onChange: any) => (
-            <Row gutter={[16, 16]}>
-              <Col span={8}>
-                <label>{t('Opacity')}</label>
-                <input
-                  type="range"
-                  min="0"
-                  max="1"
-                  step="0.1"
-                  value={values.opacity || 1}
-                  onChange={e =>
-                    onChange('opacity', parseFloat(e.target.value))
-                  }
-                />
-              </Col>
-              <Col span={8}>
-                <label>{t('Show Legend')}</label>
-                <input
-                  type="checkbox"
-                  checked={values.show_legend ?? true}
-                  onChange={e => onChange('show_legend', e.target.checked)}
-                />
-              </Col>
-              <Col span={8}>
-                <label>{t('Show Labels')}</label>
-                <input
-                  type="checkbox"
-                  checked={values.show_labels ?? false}
-                  onChange={e => onChange('show_labels', e.target.checked)}
-                />
-              </Col>
-            </Row>
-          ),
-        },
-      ],
-    },
-  ],
-};
-
-export default ModernControlPanelExample;
diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ReactControlWrappers.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ReactControlWrappers.tsx
deleted file mode 100644
index 635b507574..0000000000
--- 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ReactControlWrappers.tsx
+++ /dev/null
@@ -1,370 +0,0 @@
-/**
- * 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 } from 'react';
-import { t } from '@superset-ui/core';
-
-/**
- * React component wrappers for control panel controls.
- * These components wrap the underlying control implementations
- * to provide a React component interface for modern control panels.
- */
-
-interface ControlProps {
-  value?: any;
-  onChange: (name: string, value: any) => void;
-  datasource?: any;
-  [key: string]: any;
-}
-
-/**
- * GroupBy control component
- */
-export const GroupBy: FC<ControlProps> = ({ value, onChange, ...props }) => (
-  // This would normally render the actual DndColumnSelect component
-  // For now, return a placeholder
-  <div className="control-wrapper">
-    <label>{t('Group by')}</label>
-    <div className="groupby-control">
-      {/* DndColumnSelect would go here */}
-      <input
-        type="text"
-        value={JSON.stringify(value || [])}
-        onChange={e => {
-          try {
-            onChange('groupby', JSON.parse(e.target.value));
-          } catch {
-            // Invalid JSON
-          }
-        }}
-        placeholder={t('Select columns')}
-      />
-    </div>
-    <small className="text-muted">{t('One or many columns to group 
by')}</small>
-  </div>
-);
-
-/**
- * Metrics control component
- */
-export const Metrics: FC<ControlProps> = ({ value, onChange, ...props }) => (
-  <div className="control-wrapper">
-    <label>{t('Metrics')}</label>
-    <div className="metrics-control">
-      {/* DndMetricSelect would go here */}
-      <input
-        type="text"
-        value={JSON.stringify(value || [])}
-        onChange={e => {
-          try {
-            onChange('metrics', JSON.parse(e.target.value));
-          } catch {
-            // Invalid JSON
-          }
-        }}
-        placeholder={t('Select metrics')}
-      />
-    </div>
-    <small className="text-muted">{t('One or many metrics to display')}</small>
-  </div>
-);
-
-/**
- * AdhocFilters control component
- */
-export const AdhocFilters: FC<ControlProps> = ({
-  value,
-  onChange,
-  ...props
-}) => (
-  <div className="control-wrapper">
-    <label>{t('Filters')}</label>
-    <div className="adhoc-filters-control">
-      {/* AdhocFilterControl would go here */}
-      <input
-        type="text"
-        value={JSON.stringify(value || [])}
-        onChange={e => {
-          try {
-            onChange('adhoc_filters', JSON.parse(e.target.value));
-          } catch {
-            // Invalid JSON
-          }
-        }}
-        placeholder={t('Add filters')}
-      />
-    </div>
-    <small className="text-muted">{t('Filters to apply to the data')}</small>
-  </div>
-);
-
-/**
- * RowLimit control component
- */
-export const RowLimit: FC<ControlProps> = ({ value, onChange, ...props }) => (
-  <div className="control-wrapper">
-    <label>{t('Row limit')}</label>
-    <input
-      type="number"
-      value={value || 100}
-      onChange={e => onChange('row_limit', parseInt(e.target.value, 10))}
-      min={1}
-      max={100000}
-    />
-    <small className="text-muted">
-      {t('Maximum number of rows to display')}
-    </small>
-  </div>
-);
-
-/**
- * ColorScheme control component
- */
-export const ColorScheme: FC<ControlProps> = ({
-  value,
-  onChange,
-  ...props
-}) => (
-  // This would normally render the actual ColorSchemeControlWrapper
-  <div className="control-wrapper">
-    <label>{t('Color scheme')}</label>
-    <select
-      value={value || 'supersetColors'}
-      onChange={e => onChange('color_scheme', e.target.value)}
-    >
-      <option value="supersetColors">Superset Colors</option>
-      <option value="googleCategory10c">Google Category 10c</option>
-      <option value="d3Category10">D3 Category 10</option>
-      <option value="d3Category20">D3 Category 20</option>
-      <option value="d3Category20b">D3 Category 20b</option>
-      <option value="d3Category20c">D3 Category 20c</option>
-    </select>
-    <small className="text-muted">{t('Color scheme for the chart')}</small>
-  </div>
-);
-
-/**
- * CurrencyFormat control component
- */
-export const CurrencyFormat: FC<ControlProps> = ({
-  value,
-  onChange,
-  ...props
-}) => (
-  <div className="control-wrapper">
-    <label>{t('Currency format')}</label>
-    <select
-      value={value || 'USD'}
-      onChange={e => onChange('currency_format', e.target.value)}
-    >
-      <option value="USD">USD ($)</option>
-      <option value="EUR">EUR (€)</option>
-      <option value="GBP">GBP (£)</option>
-      <option value="JPY">JPY (¥)</option>
-      <option value="CNY">CNY (¥)</option>
-      <option value="INR">INR (₹)</option>
-    </select>
-    <small className="text-muted">{t('Currency to use for formatting')}</small>
-  </div>
-);
-
-/**
- * CheckboxControl component
- */
-export const CheckboxControl: FC<{
-  name: string;
-  label: string;
-  value?: boolean;
-  onChange: (name: string, value: any) => void;
-  description?: string;
-  disabled?: boolean;
-}> = ({ name, label, value, onChange, description, disabled }) => (
-  <div className="control-wrapper">
-    <label style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
-      <input
-        type="checkbox"
-        checked={value ?? false}
-        onChange={e => onChange(name, e.target.checked)}
-        disabled={disabled}
-      />
-      {label}
-    </label>
-    {description && <small className="text-muted">{description}</small>}
-  </div>
-);
-
-/**
- * NumberControl component
- */
-export const NumberControl: FC<{
-  name: string;
-  label: string;
-  value?: number;
-  onChange: (name: string, value: any) => void;
-  description?: string;
-  min?: number;
-  max?: number;
-  step?: number;
-}> = ({ name, label, value, onChange, description, min, max, step }) => (
-  <div className="control-wrapper">
-    <label>{label}</label>
-    <input
-      type="number"
-      value={value ?? 0}
-      onChange={e => onChange(name, parseFloat(e.target.value))}
-      min={min}
-      max={max}
-      step={step}
-    />
-    {description && <small className="text-muted">{description}</small>}
-  </div>
-);
-
-/**
- * SelectControl component
- */
-export const SelectControl: FC<{
-  name: string;
-  label: string;
-  value?: any;
-  onChange: (name: string, value: any) => void;
-  description?: string;
-  choices?: Array<[any, string]>;
-  freeForm?: boolean;
-  tokenSeparators?: string[];
-  disabled?: boolean;
-}> = ({
-  name,
-  label,
-  value,
-  onChange,
-  description,
-  choices = [],
-  disabled,
-}) => (
-  <div className="control-wrapper">
-    <label>{label}</label>
-    <select
-      value={value ?? ''}
-      onChange={e => onChange(name, e.target.value)}
-      disabled={disabled}
-    >
-      <option value="">Select...</option>
-      {choices.map(([val, text]) => (
-        <option key={val} value={val}>
-          {text}
-        </option>
-      ))}
-    </select>
-    {description && <small className="text-muted">{description}</small>}
-  </div>
-);
-
-/**
- * SliderControl component
- */
-export const SliderControl: FC<{
-  name: string;
-  label: string;
-  value?: number;
-  onChange: (name: string, value: any) => void;
-  description?: string;
-  min?: number;
-  max?: number;
-  step?: number;
-}> = ({
-  name,
-  label,
-  value,
-  onChange,
-  description,
-  min = 0,
-  max = 100,
-  step = 1,
-}) => (
-  <div className="control-wrapper">
-    <label>
-      {label}: {value ?? min}
-    </label>
-    <input
-      type="range"
-      value={value ?? min}
-      onChange={e => onChange(name, parseFloat(e.target.value))}
-      min={min}
-      max={max}
-      step={step}
-      style={{ width: '100%' }}
-    />
-    {description && <small className="text-muted">{description}</small>}
-  </div>
-);
-
-/**
- * TextControl component
- */
-export const TextControl: FC<{
-  name: string;
-  label: string;
-  value?: string;
-  onChange: (name: string, value: any) => void;
-  description?: string;
-  placeholder?: string;
-  isFloat?: boolean;
-  disabled?: boolean;
-}> = ({
-  name,
-  label,
-  value,
-  onChange,
-  description,
-  placeholder,
-  isFloat,
-  disabled,
-}) => (
-  <div className="control-wrapper">
-    <label>{label}</label>
-    <input
-      type="text"
-      value={value ?? ''}
-      onChange={e => {
-        const val = e.target.value;
-        onChange(name, isFloat ? parseFloat(val) || val : val);
-      }}
-      placeholder={placeholder}
-      disabled={disabled}
-    />
-    {description && <small className="text-muted">{description}</small>}
-  </div>
-);
-
-/**
- * Export all control components
- */
-export default {
-  GroupBy,
-  Metrics,
-  AdhocFilters,
-  RowLimit,
-  ColorScheme,
-  CurrencyFormat,
-  CheckboxControl,
-  NumberControl,
-  SelectControl,
-  SliderControl,
-  TextControl,
-};
diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/index.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/index.tsx
index 52bdac1858..b64952ae4d 100644
--- 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/index.tsx
+++ 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/index.tsx
@@ -54,7 +54,4 @@ export { ReactControlPanel } from './ReactControlPanel';
 // Export control panel layout components
 export * from './ControlPanelLayout';
 
-// Export React control wrappers for modern panels
-export * from './ReactControlWrappers';
-
 // Inline control functions are exported from SharedControlComponents
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanelModern.tsx 
b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanelModern.tsx
index 9556f32f00..f600713c74 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanelModern.tsx
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanelModern.tsx
@@ -16,9 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { FC } from 'react';
-import { ensureIsInt, t, validateNonEmpty } from '@superset-ui/core';
-import { Row, Col, Collapse } from '@superset-ui/core/components';
+import { t } from '@superset-ui/core';
 import {
   ControlPanelConfig,
   D3_FORMAT_DOCS,
@@ -27,464 +25,357 @@ import {
   D3_TIME_FORMAT_OPTIONS,
   getStandardizedControls,
   sharedControls,
-  // Import the actual React components
-  CheckboxControl,
-  NumberControl,
-  SelectControl,
-  SliderControl,
-  TextControl,
-  // Import React control wrappers
-  GroupBy,
-  Metrics,
-  AdhocFilters,
-  RowLimit,
-  ColorScheme,
-  CurrencyFormat,
 } from '@superset-ui/chart-controls';
 import { DEFAULT_FORM_DATA } from './types';
 
-const {
-  donut,
-  innerRadius,
-  labelsOutside,
-  labelType,
-  labelLine,
-  outerRadius,
-  numberFormat,
-  showLabels,
-  roseType,
-} = DEFAULT_FORM_DATA;
-
-/**
- * Modern React-based control panel configuration
- */
-interface ModernPieControlPanelProps {
-  values: Record<string, any>;
-  onChange: (name: string, value: any) => void;
-  datasource?: any;
-  formData?: any;
-  validationErrors?: Record<string, string[]>;
-}
-
-/**
- * Query Section Component
- */
-const QuerySection: FC<ModernPieControlPanelProps> = ({ values, onChange }) => 
(
-  <>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <GroupBy value={values.groupby} onChange={onChange} />
-      </Col>
-    </Row>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <Metrics value={values.metrics} onChange={onChange} />
-      </Col>
-    </Row>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <AdhocFilters value={values.adhoc_filters} onChange={onChange} />
-      </Col>
-    </Row>
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <RowLimit value={values.row_limit} onChange={onChange} />
-      </Col>
-      <Col span={12}>
-        <CheckboxControl
-          name="sort_by_metric"
-          label={t('Sort by Metric')}
-          value={values.sort_by_metric ?? true}
-          onChange={onChange}
-          description={t('Sort series by metric values')}
-        />
-      </Col>
-    </Row>
-  </>
-);
-
 /**
- * Chart Options Section Component
+ * Modern Pie Chart Control Panel using the existing control infrastructure
+ * This version creates individual control items that work with the current 
system
  */
-const ChartOptionsSection: FC<ModernPieControlPanelProps> = ({
-  values,
-  onChange,
-}) => (
-  <>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <ColorScheme value={values.color_scheme} onChange={onChange} />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <TextControl
-          name="show_labels_threshold"
-          label={t('Percentage threshold')}
-          value={values.show_labels_threshold ?? 5}
-          onChange={onChange}
-          description={t(
-            'Minimum threshold in percentage points for showing labels.',
-          )}
-          isFloat
-        />
-      </Col>
-      <Col span={12}>
-        <NumberControl
-          name="threshold_for_other"
-          label={t('Threshold for Other')}
-          value={values.threshold_for_other ?? 0}
-          onChange={onChange}
-          min={0}
-          max={100}
-          step={0.5}
-          description={t(
-            'Values less than this percentage will be grouped into the Other 
category.',
-          )}
-        />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <SelectControl
-          name="roseType"
-          label={t('Rose Type')}
-          value={values.roseType ?? roseType}
-          onChange={onChange}
-          choices={[
-            ['area', t('Area')],
-            ['radius', t('Radius')],
-            [null, t('None')],
-          ]}
-          description={t('Whether to show as Nightingale chart.')}
-        />
-      </Col>
-    </Row>
-  </>
-);
-
-/**
- * Legend Section Component
- */
-const LegendSection: FC<ModernPieControlPanelProps> = ({
-  values,
-  onChange,
-}) => (
-  <>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <CheckboxControl
-          name="show_legend"
-          label={t('Show legend')}
-          value={values.show_legend}
-          onChange={onChange}
-          description={t('Whether to display a legend for the chart')}
-        />
-      </Col>
-    </Row>
-
-    {values.show_legend && (
-      <>
-        <Row gutter={[16, 16]}>
-          <Col span={12}>
-            <SelectControl
-              name="legendType"
-              label={t('Legend type')}
-              value={values.legendType}
-              onChange={onChange}
-              choices={[
+const config: ControlPanelConfig = {
+  controlPanelSections: [
+    {
+      label: t('Query'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'groupby',
+            config: sharedControls.groupby || {},
+          },
+        ],
+        [
+          {
+            name: 'metric',
+            config: sharedControls.metrics || {},
+          },
+        ],
+        [
+          {
+            name: 'adhoc_filters',
+            config: sharedControls.adhoc_filters || {},
+          },
+        ],
+        [
+          {
+            name: 'row_limit',
+            config: {
+              ...sharedControls.row_limit,
+              default: 100,
+            },
+          },
+        ],
+        [
+          {
+            name: 'sort_by_metric',
+            config: sharedControls.sort_by_metric || {},
+          },
+        ],
+      ],
+    },
+    {
+      label: t('Chart Options'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'color_scheme',
+            config: sharedControls.color_scheme || {},
+          },
+        ],
+        [
+          {
+            name: 'show_labels_threshold',
+            config: {
+              type: 'TextControl',
+              label: t('Percentage threshold'),
+              renderTrigger: true,
+              isFloat: true,
+              default: 5,
+              description: t(
+                'Minimum threshold in percentage points for showing labels.',
+              ),
+            },
+          },
+          {
+            name: 'threshold_for_other',
+            config: {
+              type: 'TextControl',
+              label: t('Threshold for Other'),
+              renderTrigger: true,
+              isFloat: true,
+              default: 0,
+              description: t(
+                'Values less than this percentage will be grouped into the 
Other category.',
+              ),
+            },
+          },
+        ],
+        [
+          {
+            name: 'roseType',
+            config: {
+              type: 'SelectControl',
+              label: t('Rose Type'),
+              description: t('Whether to show as Nightingale chart.'),
+              renderTrigger: true,
+              choices: [
+                ['area', t('Area')],
+                ['radius', t('Radius')],
+                [null, t('None')],
+              ],
+              default: null,
+              clearable: false,
+            },
+          },
+        ],
+      ],
+    },
+    {
+      label: t('Labels'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'label_type',
+            config: {
+              type: 'SelectControl',
+              label: t('Label Type'),
+              default: 'key',
+              renderTrigger: true,
+              choices: [
+                ['key', t('Category Name')],
+                ['value', t('Value')],
+                ['percent', t('Percentage')],
+                ['key_value', t('Category and Value')],
+                ['key_percent', t('Category and Percentage')],
+                ['key_value_percent', t('Category, Value and Percentage')],
+                ['value_percent', t('Value and Percentage')],
+                ['template', t('Template')],
+              ],
+              description: t('What should be shown on the label?'),
+              clearable: false,
+            },
+          },
+        ],
+        [
+          {
+            name: 'label_template',
+            config: {
+              type: 'TextControl',
+              label: t('Label Template'),
+              renderTrigger: true,
+              description: t(
+                'Format data labels. Use variables: {name}, {value}, 
{percent}.',
+              ),
+              visibility: ({ controls }) =>
+                controls?.label_type?.value === 'template',
+            },
+          },
+        ],
+        [
+          {
+            name: 'number_format',
+            config: {
+              type: 'SelectControl',
+              freeForm: true,
+              label: t('Number format'),
+              renderTrigger: true,
+              default: 'SMART_NUMBER',
+              choices: D3_FORMAT_OPTIONS,
+              description: D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+            },
+          },
+          {
+            name: 'date_format',
+            config: {
+              type: 'SelectControl',
+              freeForm: true,
+              label: t('Date format'),
+              renderTrigger: true,
+              choices: D3_TIME_FORMAT_OPTIONS,
+              default: 'smart_date',
+              description: D3_FORMAT_DOCS,
+            },
+          },
+        ],
+        [
+          {
+            name: 'show_labels',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Show Labels'),
+              renderTrigger: true,
+              default: DEFAULT_FORM_DATA.showLabels,
+              description: t('Whether to display the labels.'),
+            },
+          },
+          {
+            name: 'labels_outside',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Put labels outside'),
+              renderTrigger: true,
+              default: DEFAULT_FORM_DATA.labelsOutside,
+              description: t('Put the labels outside of the pie?'),
+            },
+          },
+          {
+            name: 'label_line',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Label Line'),
+              renderTrigger: true,
+              default: DEFAULT_FORM_DATA.labelLine,
+              description: t(
+                'Draw line from Pie to label when labels outside?',
+              ),
+            },
+          },
+        ],
+        [
+          {
+            name: 'show_total',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Show Total'),
+              renderTrigger: true,
+              default: false,
+              description: t('Whether to display the aggregate count'),
+            },
+          },
+        ],
+      ],
+    },
+    {
+      label: t('Pie shape'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'outerRadius',
+            config: {
+              type: 'SliderControl',
+              label: t('Outer Radius'),
+              renderTrigger: true,
+              min: 10,
+              max: 100,
+              step: 1,
+              default: DEFAULT_FORM_DATA.outerRadius,
+              description: t('Outer edge of Pie chart'),
+            },
+          },
+        ],
+        [
+          {
+            name: 'donut',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Donut'),
+              renderTrigger: true,
+              default: DEFAULT_FORM_DATA.donut,
+              description: t('Do you want a donut or a pie?'),
+            },
+          },
+        ],
+        [
+          {
+            name: 'innerRadius',
+            config: {
+              type: 'SliderControl',
+              label: t('Inner Radius'),
+              renderTrigger: true,
+              min: 0,
+              max: 100,
+              step: 1,
+              default: DEFAULT_FORM_DATA.innerRadius,
+              description: t('Inner radius of donut hole'),
+              visibility: ({ controls }) => Boolean(controls?.donut?.value),
+            },
+          },
+        ],
+      ],
+    },
+    {
+      label: t('Legend'),
+      expanded: true,
+      controlSetRows: [
+        [
+          {
+            name: 'show_legend',
+            config: {
+              type: 'CheckboxControl',
+              label: t('Show legend'),
+              renderTrigger: true,
+              default: true,
+              description: t('Whether to display a legend for the chart'),
+            },
+          },
+        ],
+        [
+          {
+            name: 'legendType',
+            config: {
+              type: 'SelectControl',
+              label: t('Legend type'),
+              renderTrigger: true,
+              choices: [
                 ['scroll', t('Scroll')],
                 ['plain', t('Plain')],
-              ]}
-              description={t('Legend type')}
-            />
-          </Col>
-          <Col span={12}>
-            <SelectControl
-              name="legendOrientation"
-              label={t('Legend orientation')}
-              value={values.legendOrientation}
-              onChange={onChange}
-              choices={[
+              ],
+              default: 'scroll',
+              clearable: false,
+              description: t('Legend type'),
+              visibility: ({ controls }) =>
+                Boolean(controls?.show_legend?.value),
+            },
+          },
+          {
+            name: 'legendOrientation',
+            config: {
+              type: 'SelectControl',
+              label: t('Legend orientation'),
+              renderTrigger: true,
+              choices: [
                 ['top', t('Top')],
                 ['bottom', t('Bottom')],
                 ['left', t('Left')],
                 ['right', t('Right')],
-              ]}
-              description={t('Legend orientation')}
-            />
-          </Col>
-        </Row>
-
-        <Row gutter={[16, 16]}>
-          <Col span={24}>
-            <NumberControl
-              name="legendMargin"
-              label={t('Legend margin')}
-              value={values.legendMargin}
-              onChange={onChange}
-              min={0}
-              max={100}
-              description={t(
-                'Additional margin to add between legend and chart',
-              )}
-            />
-          </Col>
-        </Row>
-      </>
-    )}
-  </>
-);
-
-/**
- * Labels Section Component
- */
-const LabelsSection: FC<ModernPieControlPanelProps> = ({
-  values,
-  onChange,
-}) => (
-  <>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <SelectControl
-          name="label_type"
-          label={t('Label Type')}
-          value={values.label_type ?? labelType}
-          onChange={onChange}
-          choices={[
-            ['key', t('Category Name')],
-            ['value', t('Value')],
-            ['percent', t('Percentage')],
-            ['key_value', t('Category and Value')],
-            ['key_percent', t('Category and Percentage')],
-            ['key_value_percent', t('Category, Value and Percentage')],
-            ['value_percent', t('Value and Percentage')],
-            ['template', t('Template')],
-          ]}
-          description={t('What should be shown on the label?')}
-        />
-      </Col>
-    </Row>
-
-    {values.label_type === 'template' && (
-      <Row gutter={[16, 16]}>
-        <Col span={24}>
-          <TextControl
-            name="label_template"
-            label={t('Label Template')}
-            value={values.label_template}
-            onChange={onChange}
-            description={t(
-              'Format data labels. ' +
-                'Use variables: {name}, {value}, {percent}. ' +
-                '\\n represents a new line. ' +
-                'ECharts compatibility:\n' +
-                '{a} (series), {b} (name), {c} (value), {d} (percentage)',
-            )}
-          />
-        </Col>
-      </Row>
-    )}
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <SelectControl
-          name="number_format"
-          label={t('Number format')}
-          value={values.number_format ?? numberFormat}
-          onChange={onChange}
-          choices={D3_FORMAT_OPTIONS}
-          freeForm
-          tokenSeparators={['\n', '\t', ';']}
-          description={`${D3_FORMAT_DOCS} 
${D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT}`}
-        />
-      </Col>
-      <Col span={12}>
-        <CurrencyFormat value={values.currency_format} onChange={onChange} />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <SelectControl
-          name="date_format"
-          label={t('Date format')}
-          value={values.date_format ?? 'smart_date'}
-          onChange={onChange}
-          choices={D3_TIME_FORMAT_OPTIONS}
-          freeForm
-          description={D3_FORMAT_DOCS}
-        />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={8}>
-        <CheckboxControl
-          name="show_labels"
-          label={t('Show Labels')}
-          value={values.show_labels ?? showLabels}
-          onChange={onChange}
-          description={t('Whether to display the labels.')}
-        />
-      </Col>
-      <Col span={8}>
-        <CheckboxControl
-          name="labels_outside"
-          label={t('Put labels outside')}
-          value={values.labels_outside ?? labelsOutside}
-          onChange={onChange}
-          description={t('Put the labels outside of the pie?')}
-          disabled={!values.show_labels}
-        />
-      </Col>
-      <Col span={8}>
-        <CheckboxControl
-          name="label_line"
-          label={t('Label Line')}
-          value={values.label_line ?? labelLine}
-          onChange={onChange}
-          description={t('Draw line from Pie to label when labels outside?')}
-          disabled={!values.show_labels}
-        />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <CheckboxControl
-          name="show_total"
-          label={t('Show Total')}
-          value={values.show_total ?? false}
-          onChange={onChange}
-          description={t('Whether to display the aggregate count')}
-        />
-      </Col>
-    </Row>
-  </>
-);
-
-/**
- * Pie Shape Section Component
- */
-const PieShapeSection: FC<ModernPieControlPanelProps> = ({
-  values,
-  onChange,
-}) => (
-  <>
-    <Row gutter={[16, 16]}>
-      <Col span={24}>
-        <SliderControl
-          name="outerRadius"
-          label={t('Outer Radius')}
-          value={values.outerRadius ?? outerRadius}
-          onChange={onChange}
-          min={10}
-          max={100}
-          step={1}
-          description={t('Outer edge of Pie chart')}
-        />
-      </Col>
-    </Row>
-
-    <Row gutter={[16, 16]}>
-      <Col span={12}>
-        <CheckboxControl
-          name="donut"
-          label={t('Donut')}
-          value={values.donut ?? donut}
-          onChange={onChange}
-          description={t('Do you want a donut or a pie?')}
-        />
-      </Col>
-    </Row>
-
-    {values.donut && (
-      <Row gutter={[16, 16]}>
-        <Col span={24}>
-          <SliderControl
-            name="innerRadius"
-            label={t('Inner Radius')}
-            value={values.innerRadius ?? innerRadius}
-            onChange={onChange}
-            min={0}
-            max={100}
-            step={1}
-            description={t('Inner radius of donut hole')}
-          />
-        </Col>
-      </Row>
-    )}
-  </>
-);
-
-/**
- * Main Modern Pie Control Panel Component
- */
-export const ModernPieControlPanel: FC<ModernPieControlPanelProps> = props => (
-  <div className="modern-pie-control-panel">
-    <Collapse defaultActiveKey={['query', 'chart-options']} ghost>
-      <Collapse.Panel header={t('Query')} key="query">
-        <QuerySection {...props} />
-      </Collapse.Panel>
-
-      <Collapse.Panel header={t('Chart Options')} key="chart-options">
-        <ChartOptionsSection {...props} />
-
-        <div style={{ marginTop: 24 }}>
-          <h4>{t('Legend')}</h4>
-          <LegendSection {...props} />
-        </div>
-
-        <div style={{ marginTop: 24 }}>
-          <h4>{t('Labels')}</h4>
-          <LabelsSection {...props} />
-        </div>
-
-        <div style={{ marginTop: 24 }}>
-          <h4>{t('Pie shape')}</h4>
-          <PieShapeSection {...props} />
-        </div>
-      </Collapse.Panel>
-    </Collapse>
-  </div>
-);
-
-/**
- * Create a backward-compatible control panel config
- * This allows the modern panel to work with the existing system
- */
-export const createBackwardCompatibleConfig = (): ControlPanelConfig => ({
-  controlPanelSections: [
-    {
-      label: t('Modern Control Panel'),
-      expanded: true,
-      controlSetRows: [
+              ],
+              default: 'top',
+              clearable: false,
+              description: t('Legend orientation'),
+              visibility: ({ controls }) =>
+                Boolean(controls?.show_legend?.value),
+            },
+          },
+        ],
         [
-          // Wrap the entire modern panel as a single React element
-          <ModernPieControlPanel values={{}} onChange={() => {}} />,
+          {
+            name: 'legendMargin',
+            config: {
+              type: 'TextControl',
+              label: t('Legend margin'),
+              renderTrigger: true,
+              isInt: true,
+              default: 0,
+              description: t(
+                'Additional margin to add between legend and chart',
+              ),
+              visibility: ({ controls }) =>
+                Boolean(controls?.show_legend?.value),
+            },
+          },
         ],
       ],
     },
   ],
-  controlOverrides: {
-    series: {
-      validators: [validateNonEmpty],
-      clearable: false,
-    },
-    row_limit: {
-      default: 100,
-    },
-  },
   formDataOverrides: formData => ({
     ...formData,
     metric: getStandardizedControls().shiftMetric(),
     groupby: getStandardizedControls().popAllColumns(),
-    row_limit:
-      ensureIsInt(formData.row_limit, 100) >= 100 ? 100 : formData.row_limit,
+    row_limit: formData.row_limit ?? 100,
   }),
-});
+};
 
-export default createBackwardCompatibleConfig();
+export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts 
b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts
index 88d6e598b3..faaf3569b3 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts
@@ -18,7 +18,8 @@
  */
 import { Behavior, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-import controlPanel from './controlPanel';
+// Use the modern control panel with proper Redux integration
+import controlPanel from './controlPanelModern';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/Pie1.jpg';
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts
 
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts
index f2a9155550..f0e371b841 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Bar/index.ts
@@ -24,7 +24,7 @@ import {
 } from '../../types';
 import { EchartsChartPlugin } from '../../../types';
 import buildQuery from '../../buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from '../../../emptyControlPanel';
 import transformProps from '../../transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/Bar1.png';
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts
 
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts
index a63168617d..c309f167cf 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/Line/index.ts
@@ -23,7 +23,7 @@ import {
   EchartsTimeseriesSeriesType,
 } from '../../types';
 import buildQuery from '../../buildQuery';
-import controlPanel from './controlPanel';
+import controlPanel from '../../../emptyControlPanel';
 import transformProps from '../../transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/Line1.png';
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/emptyControlPanel.ts 
b/superset-frontend/plugins/plugin-chart-echarts/src/emptyControlPanel.ts
new file mode 100644
index 0000000000..dbc06dc11f
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/emptyControlPanel.ts
@@ -0,0 +1,36 @@
+/**
+ * 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 { t } from '@superset-ui/core';
+import { ControlPanelConfig } from '@superset-ui/chart-controls';
+
+/**
+ * Temporary empty control panel for migration.
+ * This is a placeholder while we migrate to the new React-based control 
system.
+ */
+const config: ControlPanelConfig = {
+  controlPanelSections: [
+    {
+      label: t('Migration in Progress'),
+      expanded: true,
+      controlSetRows: [],
+    },
+  ],
+};
+
+export default config;
diff --git 
a/superset-frontend/src/explore/components/ModernControlPanelRenderer.tsx 
b/superset-frontend/src/explore/components/ModernControlPanelRenderer.tsx
index 2ecdb40cb0..323d4036c2 100644
--- a/superset-frontend/src/explore/components/ModernControlPanelRenderer.tsx
+++ b/superset-frontend/src/explore/components/ModernControlPanelRenderer.tsx
@@ -63,25 +63,29 @@ export const ModernControlPanelRenderer: FC<
 }) => {
   // Check if this is a modern control panel component
   // Modern panels will have specific prop expectations
+  const elementType = element.type as any;
   const isModernPanel =
     element.props &&
-    ('values' in element.props ||
+    ('value' in element.props ||
       'onChange' in element.props ||
-      element.type?.name?.includes('Modern'));
+      elementType?.name?.includes('PieControlPanel') ||
+      elementType?.name?.includes('Modern'));
 
   if (!isModernPanel) {
     // If it's not a modern panel, render as-is
     return element;
   }
 
-  // Create the modern props adapter
-  const modernProps: ModernControlPanelProps = {
-    values: formData,
+  // Create the modern props adapter for the new naming convention
+  const modernProps = {
+    value: formData,
     onChange: (name: string, value: JsonValue) => {
       actions.setControlValue(name, value);
     },
     datasource,
+    controls,
     formData,
+    actions,
     validationErrors,
   };
 
@@ -98,10 +102,12 @@ export const isModernControlPanel = (element: any): 
boolean => {
   }
 
   const elementType = element.type as any;
+  const props = element.props as any;
   return (
+    elementType?.name?.includes('PieControlPanel') ||
     elementType?.name?.includes('Modern') ||
     elementType?.displayName?.includes('Modern') ||
-    element.props?.isModernPanel === true
+    props?.isModernPanel === true
   );
 };
 
@@ -111,7 +117,7 @@ export const isModernControlPanel = (element: any): boolean 
=> {
 export function withModernPanelMarker<P extends ModernControlPanelProps>(
   Component: FC<P>,
 ): FC<P> {
-  const WrappedComponent: FC<P> = props => <Component {...props} />;
+  const WrappedComponent: FC<P> = props => <Component {...(props as P)} />;
 
   WrappedComponent.displayName = `Modern${Component.displayName || 
Component.name}`;
 

Reply via email to