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 3603775df1e63a12c0794bb1502a67cbdb6a82e1
Author: Evan Rusackas <[email protected]>
AuthorDate: Thu Aug 14 10:47:51 2025 -0700

    feat: Create TRUE React-based control panel for Pie chart
    
    - Complete abandonment of controlPanelSections/controlSetRows architecture
    - Use Ant Design Collapse and Grid for layout instead of proprietary 
constructs
    - Import actual React control components from controlMap
    - Direct component usage, no config objects
    - Clean, modern React component approach with proper props
    
    This is the actual React-based control panel we want - pure components,
    no legacy structures, just React + Ant Design.
---
 .../src/Pie/PieControlPanel.tsx                    | 433 +++++++++++++++++++++
 .../plugins/plugin-chart-echarts/src/Pie/index.ts  |   4 +-
 2 files changed, 435 insertions(+), 2 deletions(-)

diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/PieControlPanel.tsx 
b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/PieControlPanel.tsx
new file mode 100644
index 0000000000..a3fce3338f
--- /dev/null
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/PieControlPanel.tsx
@@ -0,0 +1,433 @@
+/**
+ * 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 { Collapse, Row, Col, Typography } from 'antd';
+import { 
+  ControlPanelConfig,
+  D3_FORMAT_OPTIONS,
+  D3_NUMBER_FORMAT_DESCRIPTION_VALUES_TEXT,
+  D3_TIME_FORMAT_OPTIONS,
+  D3_FORMAT_DOCS,
+} from '@superset-ui/chart-controls';
+
+// Import the control map which contains all control components
+import controlMap from 'src/explore/components/controls';
+
+import { DEFAULT_FORM_DATA } from './types';
+
+const { Panel } = Collapse;
+const { Title } = Typography;
+
+interface PieControlPanelProps {
+  onChange: (field: string, value: any) => void;
+  value: Record<string, any>;
+  datasource: any;
+  actions?: any;
+  controls?: any;
+  form_data?: any;
+}
+
+/**
+ * A TRUE React component-based control panel for Pie charts.
+ * No legacy controlPanelSections, no controlSetRows, no config objects.
+ * Just pure React components with Ant Design layout.
+ */
+export const PieControlPanel: FC<PieControlPanelProps> = ({ 
+  onChange, 
+  value, 
+  datasource,
+  form_data,
+}) => {
+  // Get control components from controlMap
+  const DndColumnSelect = controlMap.DndColumnSelect;
+  const DndMetricSelect = controlMap.DndMetricSelect;
+  const AdhocFilterControl = controlMap.AdhocFilterControl;
+  const CheckboxControl = controlMap.CheckboxControl;
+  const SelectControl = controlMap.SelectControl;
+  const TextControl = controlMap.TextControl;
+  const SliderControl = controlMap.SliderControl;
+  const ColorSchemeControl = controlMap.ColorSchemeControl;
+  
+  // Helper to handle control changes
+  const handleChange = (field: string) => (val: any) => {
+    onChange(field, val);
+  };
+
+  return (
+    <div style={{ padding: '16px' }}>
+      <Collapse defaultActiveKey={['query', 'chart', 'labels', 'pie', 
'legend']} ghost>
+        {/* Query Section */}
+        <Panel header={<Title level={5}>{t('Query')}</Title>} key="query">
+          <Row gutter={[16, 16]}>
+            <Col span={24}>
+              <DndColumnSelect
+                name="groupby"
+                label={t('Group by')}
+                onChange={handleChange('groupby')}
+                value={value.groupby || []}
+                datasource={datasource}
+                multi
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={24}>
+              <DndMetricSelect
+                name="metric"
+                label={t('Metric')}
+                onChange={handleChange('metric')}
+                value={value.metric}
+                datasource={datasource}
+                multi={false}
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={24}>
+              <AdhocFilterControl
+                name="adhoc_filters"
+                label={t('Filters')}
+                onChange={handleChange('adhoc_filters')}
+                value={value.adhoc_filters || []}
+                datasource={datasource}
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <TextControl
+                label={t('Row limit')}
+                onChange={handleChange('row_limit')}
+                value={value.row_limit || 100}
+                controlId="row_limit"
+                renderTrigger
+              />
+            </Col>
+            <Col span={12}>
+              <CheckboxControl
+                label={t('Sort by metric')}
+                onChange={handleChange('sort_by_metric')}
+                value={value.sort_by_metric ?? true}
+                controlId="sort_by_metric"
+                renderTrigger
+              />
+            </Col>
+          </Row>
+        </Panel>
+        
+        {/* Chart Options */}
+        <Panel header={<Title level={5}>{t('Chart Options')}</Title>} 
key="chart">
+          <Row gutter={[16, 16]}>
+            <Col span={24}>
+              <ColorSchemeControl
+                name="color_scheme"
+                label={t('Color scheme')}
+                onChange={handleChange('color_scheme')}
+                value={value.color_scheme || 'supersetColors'}
+                schemes={() => {}}
+                isLinear={false}
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <TextControl
+                label={t('Percentage threshold')}
+                
+                onChange={handleChange('show_labels_threshold')}
+                value={value.show_labels_threshold ?? 5}
+                controlId="show_labels_threshold"
+                renderTrigger
+                
+              />
+            </Col>
+            <Col span={12}>
+              <TextControl
+                label={t('Threshold for Other')}
+                
+                onChange={handleChange('threshold_for_other')}
+                value={value.threshold_for_other ?? 0}
+                controlId="threshold_for_other"
+                renderTrigger
+                
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <SelectControl
+                label={t('Rose Type')}
+                
+                onChange={handleChange('roseType')}
+                value={value.roseType || null}
+                choices={[
+                  ['area', t('Area')],
+                  ['radius', t('Radius')],
+                  [null, t('None')],
+                ]}
+                clearable={false}
+              />
+            </Col>
+          </Row>
+        </Panel>
+        
+        {/* Labels Section */}
+        <Panel header={<Title level={5}>{t('Labels')}</Title>} key="labels">
+          <Row gutter={[16, 16]}>
+            <Col span={24}>
+              <SelectControl
+                label={t('Label Type')}
+                
+                onChange={handleChange('label_type')}
+                value={value.label_type || 'key'}
+                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')],
+                ]}
+                clearable={false}
+              />
+            </Col>
+          </Row>
+          
+          {value.label_type === 'template' && (
+            <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+              <Col span={24}>
+                <TextControl
+                  label={t('Label Template')}
+                  onChange={handleChange('label_template')}
+                  value={value.label_template || ''}
+                  controlId="label_template"
+                  renderTrigger
+                />
+              </Col>
+            </Row>
+          )}
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <SelectControl
+                label={t('Number format')}
+                
+                onChange={handleChange('number_format')}
+                value={value.number_format || 'SMART_NUMBER'}
+                choices={D3_FORMAT_OPTIONS}
+                freeForm
+              />
+            </Col>
+            <Col span={12}>
+              <SelectControl
+                label={t('Date format')}
+                
+                onChange={handleChange('date_format')}
+                value={value.date_format || 'smart_date'}
+                choices={D3_TIME_FORMAT_OPTIONS}
+                freeForm
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={8}>
+              <CheckboxControl
+                label={t('Show Labels')}
+                
+                onChange={handleChange('show_labels')}
+                value={value.show_labels ?? DEFAULT_FORM_DATA.showLabels}
+                controlId="show_labels"
+                renderTrigger
+              />
+            </Col>
+            <Col span={8}>
+              <CheckboxControl
+                label={t('Put labels outside')}
+                
+                onChange={handleChange('labels_outside')}
+                value={value.labels_outside ?? DEFAULT_FORM_DATA.labelsOutside}
+                controlId="labels_outside"
+                renderTrigger
+              />
+            </Col>
+            <Col span={8}>
+              <CheckboxControl
+                label={t('Label Line')}
+                
+                onChange={handleChange('label_line')}
+                value={value.label_line ?? DEFAULT_FORM_DATA.labelLine}
+                controlId="label_line"
+                renderTrigger
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <CheckboxControl
+                label={t('Show Total')}
+                
+                onChange={handleChange('show_total')}
+                value={value.show_total ?? false}
+                controlId="show_total"
+                renderTrigger
+              />
+            </Col>
+          </Row>
+        </Panel>
+        
+        {/* Pie Shape Section */}
+        <Panel header={<Title level={5}>{t('Pie shape')}</Title>} key="pie">
+          <Row gutter={[16, 16]}>
+            <Col span={24}>
+              <SliderControl
+                label={t('Outer Radius')}
+                onChange={handleChange('outerRadius')}
+                value={value.outerRadius ?? DEFAULT_FORM_DATA.outerRadius}
+              />
+            </Col>
+          </Row>
+          
+          <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+            <Col span={12}>
+              <CheckboxControl
+                label={t('Donut')}
+                
+                onChange={handleChange('donut')}
+                value={value.donut ?? DEFAULT_FORM_DATA.donut}
+                controlId="donut"
+                renderTrigger
+              />
+            </Col>
+          </Row>
+          
+          {value.donut && (
+            <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+              <Col span={24}>
+                <SliderControl
+                  label={t('Inner Radius')}
+                  onChange={handleChange('innerRadius')}
+                  value={value.innerRadius ?? DEFAULT_FORM_DATA.innerRadius}
+                />
+              </Col>
+            </Row>
+          )}
+        </Panel>
+        
+        {/* Legend Section */}
+        <Panel header={<Title level={5}>{t('Legend')}</Title>} key="legend">
+          <Row gutter={[16, 16]}>
+            <Col span={24}>
+              <CheckboxControl
+                label={t('Show legend')}
+                
+                onChange={handleChange('show_legend')}
+                value={value.show_legend ?? true}
+                controlId="show_legend"
+                renderTrigger
+              />
+            </Col>
+          </Row>
+          
+          {value.show_legend && (
+            <>
+              <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+                <Col span={12}>
+                  <SelectControl
+                    label={t('Legend type')}
+                    
+                    onChange={handleChange('legendType')}
+                    value={value.legendType || 'scroll'}
+                    choices={[
+                      ['scroll', t('Scroll')],
+                      ['plain', t('Plain')],
+                    ]}
+                    clearable={false}
+                  />
+                </Col>
+                <Col span={12}>
+                  <SelectControl
+                    label={t('Legend orientation')}
+                    
+                    onChange={handleChange('legendOrientation')}
+                    value={value.legendOrientation || 'top'}
+                    choices={[
+                      ['top', t('Top')],
+                      ['bottom', t('Bottom')],
+                      ['left', t('Left')],
+                      ['right', t('Right')],
+                    ]}
+                    clearable={false}
+                  />
+                </Col>
+              </Row>
+              
+              <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
+                <Col span={24}>
+                  <TextControl
+                    label={t('Legend margin')}
+                    
+                    onChange={handleChange('legendMargin')}
+                    value={value.legendMargin || 0}
+                    controlId="legendMargin"
+                    renderTrigger
+                    
+                  />
+                </Col>
+              </Row>
+            </>
+          )}
+        </Panel>
+      </Collapse>
+    </div>
+  );
+};
+
+/**
+ * Export as a ControlPanelConfig that just contains our React component.
+ * This is the bridge between the old system and our new approach.
+ */
+const config: ControlPanelConfig = {
+  controlPanelSections: [
+    {
+      label: t('React Control Panel'),
+      expanded: true,
+      controlSetRows: [
+        [
+          <PieControlPanel
+            onChange={() => {}}
+            value={{}}
+            datasource={{}}
+          />,
+        ],
+      ],
+    },
+  ],
+};
+
+export default config;
\ No newline at end of file
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 faaf3569b3..53e0319929 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/index.ts
@@ -18,8 +18,8 @@
  */
 import { Behavior, t } from '@superset-ui/core';
 import buildQuery from './buildQuery';
-// Use the modern control panel with proper Redux integration
-import controlPanel from './controlPanelModern';
+// Use the TRUE React component-based control panel
+import controlPanel from './PieControlPanel';
 import transformProps from './transformProps';
 import thumbnail from './images/thumbnail.png';
 import example1 from './images/Pie1.jpg';

Reply via email to