korbit-ai[bot] commented on code in PR #33146:
URL: https://github.com/apache/superset/pull/33146#discussion_r2219869898


##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/types.ts:
##########
@@ -49,14 +49,20 @@
   LegendFormData & {
     increaseColor: RgbaColor;
     decreaseColor: RgbaColor;
+    orientation: 'vertical' | 'horizontal';
+    showTotal: boolean;
+    boldLabels: string;

Review Comment:
   ### Unclear property type constraints <sub>![category 
Readability](https://img.shields.io/badge/Readability-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The property name 'boldLabels' and its type (string) don't clearly indicate 
what kind of string values are valid or what this setting controls.
   
   
   ###### Why this matters
   Without clear type constraints or descriptive naming, developers will need 
to look elsewhere to understand what values are valid and what elements this 
property affects.
   
   ###### Suggested change ∙ *Feature Preview*
   ```typescript
   type BoldLabelType = 'NONE' | 'TOTAL' | 'SUBTOTAL' | 'ALL';
   boldLabels: BoldLabelType;
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/42e673a7-6f53-4496-9a9a-5944dc155c2a/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/42e673a7-6f53-4496-9a9a-5944dc155c2a?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/42e673a7-6f53-4496-9a9a-5944dc155c2a?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/42e673a7-6f53-4496-9a9a-5944dc155c2a?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/42e673a7-6f53-4496-9a9a-5944dc155c2a)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:a850bae1-61c7-4554-88af-7e2b1b754d76 -->
   
   
   [](a850bae1-61c7-4554-88af-7e2b1b754d76)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/controlPanel.tsx:
##########
@@ -34,6 +34,51 @@ const config: ControlPanelConfig = {
       expanded: true,
       controlSetRows: [
         ['x_axis'],
+        [
+          {
+            name: 'xAxisSortByColumn',
+            config: {
+              type: 'SelectControl',
+              label: t('X axis sort by column'),
+              description: t(
+                'Column to use for ordering the waterfall based on a column',
+              ),
+              mapStateToProps: state => ({
+                choices: [
+                  ...(state.datasource?.columns || []).map(col => [
+                    col.column_name,
+                    col.column_name,
+                  ]),
+                ],
+                default: '',
+              }),
+              renderTrigger: false,
+              clearable: true,
+              visibility: ({ controls }) => Boolean(controls?.x_axis?.value),
+            },
+          },
+        ],
+        [
+          {
+            name: 'xAxisSortByColumnOrder',
+            config: {
+              type: 'SelectControl',
+              label: t('X axis sort by column order direction'),
+              choices: [
+                ['NONE', t('None')],
+                ['ASC', t('Ascending')],
+                ['DESC', t('Descending')],
+              ],

Review Comment:
   ### Inconsistent enum value casing <sub>![category 
Readability](https://img.shields.io/badge/Readability-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Inconsistent string enum values. 'NONE' uses uppercase while 'ASC' and 
'DESC' also use uppercase, but 'none' is used elsewhere in the codebase for 
similar controls.
   
   
   ###### Why this matters
   Inconsistent enum values make the code harder to maintain and can lead to 
confusion when comparing values across the codebase.
   
   ###### Suggested change ∙ *Feature Preview*
   ```typescript
   choices: [
     ['none', t('None')],
     ['asc', t('Ascending')],
     ['desc', t('Descending')],
   ],
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7aaeeef9-743a-4b04-85d9-33c35bcf58f0/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7aaeeef9-743a-4b04-85d9-33c35bcf58f0?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7aaeeef9-743a-4b04-85d9-33c35bcf58f0?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7aaeeef9-743a-4b04-85d9-33c35bcf58f0?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/7aaeeef9-743a-4b04-85d9-33c35bcf58f0)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:c666dd64-84ac-4ee8-92b6-d44ff311b950 -->
   
   
   [](c666dd64-84ac-4ee8-92b6-d44ff311b950)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/EchartsWaterfall.tsx:
##########
@@ -23,9 +23,38 @@ import { EventHandlers } from '../types';
 export default function EchartsWaterfall(
   props: WaterfallChartTransformedProps,
 ) {
-  const { height, width, echartOptions, refs, onLegendStateChanged } = props;
+  const {
+    height,
+    width,
+    echartOptions,
+    setDataMask,
+    onContextMenu,
+    refs,
+    onLegendStateChanged,
+    emitCrossFilters,
+    filterState,
+    handleCrossFilter,
+  } = props;
 
   const eventHandlers: EventHandlers = {
+    click: params => {
+      if (!setDataMask || !emitCrossFilters) return;
+
+      const { name: value } = params;
+      if (value === 'Total') return;
+      const filterOptions = handleCrossFilter(
+        value,
+        filterState?.value === value,
+      );
+      if (!filterOptions) return;

Review Comment:
   ### Silent failure in cross-filter handling <sub>![category Error 
Handling](https://img.shields.io/badge/Error%20Handling-ea580c)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The early return when filterOptions is falsy silently fails without 
providing any context about why the filtering operation failed.
   
   
   ###### Why this matters
   Silent failures make it difficult to debug issues in production when 
cross-filtering operations fail unexpectedly.
   
   ###### Suggested change ∙ *Feature Preview*
   Add error logging to provide context about the failed operation:
   ```typescript
   if (!filterOptions) {
     console.warn('Cross-filtering failed: handleCrossFilter returned no filter 
options for value:', value);
     return;
   }
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6580c4c8-fb92-47c1-b382-3748a3542b1e/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6580c4c8-fb92-47c1-b382-3748a3542b1e?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6580c4c8-fb92-47c1-b382-3748a3542b1e?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6580c4c8-fb92-47c1-b382-3748a3542b1e?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/6580c4c8-fb92-47c1-b382-3748a3542b1e)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:bc0f9115-c706-4c43-b296-ecf1cacced56 -->
   
   
   [](bc0f9115-c706-4c43-b296-ecf1cacced56)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/types.ts:
##########
@@ -68,5 +74,14 @@ export interface EchartsWaterfallChartProps extends 
ChartProps {
   queriesData: ChartDataResponseResult[];
 }
 
-export type WaterfallChartTransformedProps =
-  BaseTransformedProps<EchartsWaterfallFormData>;
+export interface WaterfallChartTransformedProps
+  extends BaseTransformedProps<EchartsWaterfallFormData> {
+  emitCrossFilters?: boolean;
+  filterState?: {
+    value?: string;
+  };
+  handleCrossFilter: (
+    value: string,
+    isCurrentValue: boolean,
+  ) => { extraFormData: any; filterState: any } | null;

Review Comment:
   ### Undocumented cross-filter handler with any types <sub>![category 
Documentation](https://img.shields.io/badge/Documentation-7c3aed)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The `handleCrossFilter` function uses `any` types and lacks documentation 
explaining its purpose and return value meaning.
   
   
   ###### Why this matters
   The use of `any` without documentation makes it difficult to understand what 
data structure is expected in extraFormData and filterState.
   
   ###### Suggested change ∙ *Feature Preview*
   /** Handles cross-filtering interactions by generating filter data
      * @param value - The value to filter by
      * @param isCurrentValue - Whether the value is currently selected
      * @returns Filter configuration object or null if filtering is not 
applicable
      */
     handleCrossFilter: (
       value: string,
       isCurrentValue: boolean,
     ) => { extraFormData: any; filterState: any } | null;
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9d31044e-d85d-4cce-9d08-674db06721d6/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9d31044e-d85d-4cce-9d08-674db06721d6?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9d31044e-d85d-4cce-9d08-674db06721d6?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9d31044e-d85d-4cce-9d08-674db06721d6?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9d31044e-d85d-4cce-9d08-674db06721d6)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:c4e86f44-6757-49f9-b58b-41d49b66661d -->
   
   
   [](c4e86f44-6757-49f9-b58b-41d49b66661d)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts:
##########
@@ -156,11 +156,45 @@
     legendState,
     queriesData,
     hooks,
+    filterState,
     theme,
+    emitCrossFilters,
     inContextMenu,
   } = chartProps;
   const refs: Refs = {};
-  const { data = [] } = queriesData[0];
+  let { data = [] } = queriesData[0];
+
+  const { xAxisSortByColumn, xAxisSortByColumnOrder } = formData;
+  if (
+    xAxisSortByColumn &&
+    xAxisSortByColumnOrder &&
+    xAxisSortByColumnOrder !== 'NONE'
+  ) {
+    const sortColumn = xAxisSortByColumn;
+    const isAscending = xAxisSortByColumnOrder === 'ASC';
+
+    data = [...data].sort((a, b) => {

Review Comment:
   ### Inefficient array sorting with spread operator <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Creating a new array with spread operator and then sorting it creates 
unnecessary memory allocation for large datasets.
   
   
   ###### Why this matters
   For large datasets, this operation will consume twice the memory temporarily 
and cause extra GC pressure.
   
   ###### Suggested change ∙ *Feature Preview*
   Sort the array in place using Array.prototype.sort directly if possible:
   ```typescript
   data.sort((a, b) => {
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9fa49d2d-4359-427e-a10c-d3e8d92c1114/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9fa49d2d-4359-427e-a10c-d3e8d92c1114?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9fa49d2d-4359-427e-a10c-d3e8d92c1114?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9fa49d2d-4359-427e-a10c-d3e8d92c1114?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/9fa49d2d-4359-427e-a10c-d3e8d92c1114)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:0c13d424-d285-4072-b249-7329e2f818ca -->
   
   
   [](0c13d424-d285-4072-b249-7329e2f818ca)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts:
##########
@@ -452,14 +490,301 @@
     series: barSeries,
   };
 
+  const processSeriesData = (options: EChartsOption) => {
+    let processedOptions = { ...options };
+
+    // Handle subtotal styling
+    if (useFirstValueAsSubtotal) {
+      const processedSeries = ((options.series as any[]) || []).map(series => {
+        const newData = series.data.map((dataPoint: any, index: number) => {
+          if (index !== 0) return dataPoint;
+          if (dataPoint?.itemStyle?.color === 'transparent') return dataPoint;
+          if (dataPoint.value === '-') return dataPoint;
+
+          const updatedColor = `rgba(${totalColor.r}, ${totalColor.g}, 
${totalColor.b})`;
+          return {
+            ...dataPoint,
+            itemStyle: {
+              ...dataPoint.itemStyle,
+              color: updatedColor,
+              borderColor: updatedColor,
+            },
+          };
+        });
+
+        return {
+          ...series,
+          data: newData,
+        };
+      });
+
+      processedOptions = {
+        ...processedOptions,
+        series: processedSeries,
+      };
+    }
+
+    // Handle total visibility
+    if (!showTotal) {
+      const totalsIndex =
+        ((processedOptions.series as any[]) || [])
+          .find(series => series.name === 'Total')
+          ?.data.map((dataPoint: any, index: number) =>
+            dataPoint.value !== '-' ? index : -1,
+          )
+          .filter((index: number) => index !== -1) || [];
+
+      const filteredData = [
+        ...((processedOptions.xAxis as { data: (string | number)[] }).data ||
+          []),
+      ].filter((_, index) => !totalsIndex.includes(index));
+
+      const filteredSeries = ((processedOptions.series as any[]) || []).map(
+        series => ({
+          ...series,
+          data: series.data.filter(
+            (_: any, index: number) => !totalsIndex.includes(index),
+          ),
+        }),
+      );
+
+      processedOptions = {
+        ...processedOptions,
+        xAxis: {
+          ...(processedOptions.xAxis as any),
+          data: filteredData,
+        },
+        series: filteredSeries,
+      };
+    }
+
+    // Handle orientation
+    if (orientation === 'horizontal') {
+      processedOptions = {
+        ...processedOptions,
+        xAxis: {
+          ...((processedOptions.yAxis as any) || {}),
+          type: 'value',
+        },
+        yAxis: {
+          ...((processedOptions.xAxis as any) || {}),
+          type: 'category',
+          data: [...(processedOptions.xAxis as any).data].reverse(),
+        },
+        series: Array.isArray(processedOptions.series)
+          ? processedOptions.series.map((series: any) => ({
+              ...series,
+              encode: {
+                x: series.encode?.y,
+                y: series.encode?.x,
+              },
+              data: [...series.data].reverse(),
+              label: {
+                ...(series.label || {}),
+                position: series.name === 'Decrease' ? 'left' : 'right',
+              },
+            }))
+          : [],
+      };
+    }
+
+    return processedOptions;
+  };
+
+  // adds more formatting to previous axisLabel.formatter
+  const getFormattedAxisOptions = (options: EChartsOption) => {
+    // If no formatting needed, return original options
+    if (boldLabels === 'none' && xTicksLayout !== 'flat') {
+      return options;
+    }
+
+    // Get total indices for bold formatting
+    const totalsIndex = ['total', 'both'].includes(boldLabels)
+      ? ((options.series as any[]) || [])
+          .find(series => series.name === 'Total')
+          ?.data.map((dataPoint: any, index: number) =>
+            dataPoint.value !== '-' ? index : -1,
+          )
+          .filter((index: number) => index !== -1) || []
+      : [];

Review Comment:
   ### Inefficient chained array operations <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Chaining multiple array operations (find, map, filter) creates unnecessary 
intermediate arrays and performs multiple iterations.
   
   
   ###### Why this matters
   Each chained operation creates a new array and requires a full iteration, 
impacting performance with large datasets.
   
   ###### Suggested change ∙ *Feature Preview*
   Use a single reduce or forEach to collect indices:
   ```typescript
   const totalsIndex = ['total', 'both'].includes(boldLabels)
     ? options.series?.reduce((indices, series) => {
         if (series.name === 'Total') {
           series.data.forEach((point, idx) => {
             if (point.value !== '-') indices.push(idx);
           });
         }
         return indices;
       }, []) || []
     : [];
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8e02acd0-1c53-482e-8805-879dfa631b63/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8e02acd0-1c53-482e-8805-879dfa631b63?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8e02acd0-1c53-482e-8805-879dfa631b63?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8e02acd0-1c53-482e-8805-879dfa631b63?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8e02acd0-1c53-482e-8805-879dfa631b63)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:21a12875-1204-4c51-ab13-c13cc420d45d -->
   
   
   [](21a12875-1204-4c51-ab13-c13cc420d45d)



##########
superset-frontend/plugins/plugin-chart-echarts/src/Waterfall/transformProps.ts:
##########
@@ -156,11 +156,45 @@ export default function transformProps(
     legendState,
     queriesData,
     hooks,
+    filterState,
     theme,
+    emitCrossFilters,
     inContextMenu,
   } = chartProps;
   const refs: Refs = {};
-  const { data = [] } = queriesData[0];
+  let { data = [] } = queriesData[0];
+
+  const { xAxisSortByColumn, xAxisSortByColumnOrder } = formData;
+  if (
+    xAxisSortByColumn &&
+    xAxisSortByColumnOrder &&
+    xAxisSortByColumnOrder !== 'NONE'
+  ) {
+    const sortColumn = xAxisSortByColumn;
+    const isAscending = xAxisSortByColumnOrder === 'ASC';
+
+    data = [...data].sort((a, b) => {
+      const aValue = a[sortColumn];
+      const bValue = b[sortColumn];
+
+      // Handle null/undefined values
+      if (aValue == null && bValue == null) return 0;
+      if (aValue == null) return isAscending ? -1 : 1;
+      if (bValue == null) return isAscending ? 1 : -1;
+
+      // Handle numeric values
+      if (typeof aValue === 'number' && typeof bValue === 'number') {
+        return isAscending ? aValue - bValue : bValue - aValue;
+      }
+
+      // Handle string/other values
+      const aStr = String(aValue);
+      const bStr = String(bValue);
+      const comparison = aStr.localeCompare(bStr);

Review Comment:
   ### Inline complex sorting logic <sub>![category 
Readability](https://img.shields.io/badge/Readability-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Complex sorting logic is embedded directly in the transformProps function, 
making it difficult to understand and reuse.
   
   
   ###### Why this matters
   Inline sorting logic reduces code clarity and makes it harder to maintain 
consistent sorting behavior across the application. This logic could be reused 
elsewhere.
   
   ###### Suggested change ∙ *Feature Preview*
   Extract into a separate utility function:
   ```typescript
   const sortByColumn = <T extends Record<string, any>>(
     data: T[],
     column: keyof T,
     order: 'ASC' | 'DESC' | 'NONE'
   ): T[] => {
     if (order === 'NONE') return data;
     const isAscending = order === 'ASC';
     
     return [...data].sort((a, b) => {
       const aValue = a[column];
       const bValue = b[column];
       // ... rest of sorting logic ...
     });
   };
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8d9727df-1c30-407d-bfe6-549fd84c616c/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8d9727df-1c30-407d-bfe6-549fd84c616c?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8d9727df-1c30-407d-bfe6-549fd84c616c?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8d9727df-1c30-407d-bfe6-549fd84c616c?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/8d9727df-1c30-407d-bfe6-549fd84c616c)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:c71c4708-cef8-4777-a280-25ee929f0e12 -->
   
   
   [](c71c4708-cef8-4777-a280-25ee929f0e12)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org
For additional commands, e-mail: notifications-h...@superset.apache.org

Reply via email to