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

msyavuz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 82d6076804b refactor(charts): filter saved metrics by key and label 
(#37136)
82d6076804b is described below

commit 82d6076804b964d071f97b2acea29e8a08d4fb2d
Author: Vinícius Borges Alencar <[email protected]>
AuthorDate: Mon Feb 9 01:29:32 2026 -0300

    refactor(charts): filter saved metrics by key and label (#37136)
---
 .../ColumnSelectPopover.test.tsx                   | 128 ++++++++++++++++-
 .../DndColumnSelectControl/ColumnSelectPopover.tsx |  13 ++
 .../AdhocMetricEditPopover.test.tsx                | 158 +++++++++++++++++++++
 .../MetricControl/AdhocMetricEditPopover/index.tsx |   6 +
 4 files changed, 304 insertions(+), 1 deletion(-)

diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
index f5a2d613ced..f7046eb3203 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
@@ -17,7 +17,13 @@
  * under the License.
  */
 
-import { render, fireEvent } from 'spec/helpers/testing-library';
+import {
+  render,
+  fireEvent,
+  screen,
+  userEvent,
+  within,
+} from 'spec/helpers/testing-library';
 import configureMockStore from 'redux-mock-store';
 import thunk from 'redux-thunk';
 import ColumnSelectPopover, {
@@ -116,3 +122,123 @@ test('open with Custom SQL tab selected when there is a 
custom SQL selected', ()
   expect(getByText('Simple')).toHaveAttribute('aria-selected', 'false');
   expect(getByText('Custom SQL')).toHaveAttribute('aria-selected', 'true');
 });
+
+test('Should filter simple columns by column_name and verbose_name', async () 
=> {
+  renderPopover({
+    columns: [
+      { column_name: 'revenue_amount', verbose_name: 'Total Sales' },
+      { column_name: 'user_id', verbose_name: 'User Identifier' },
+      { column_name: 'created_at', verbose_name: 'Creation Date' },
+      { column_name: 'order_status', verbose_name: 'Status' },
+      { column_name: 'updated_at', verbose_name: 'Last Update' },
+    ],
+    editedColumn: undefined,
+    getCurrentTab: jest.fn(),
+    onChange: jest.fn(),
+  });
+
+  const combobox = screen.getByRole('combobox', {
+    name: 'Columns and metrics',
+  });
+
+  await userEvent.type(combobox, 'revenue');
+
+  let dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Total Sales')).toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('User Identifier'),
+  ).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Creation 
Date')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Status')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Last Update')).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, 'Identifier');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('User Identifier')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Sales')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Creation 
Date')).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, '_at');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Creation Date')).toBeInTheDocument();
+  expect(within(dropdown).getByText('Last Update')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Sales')).not.toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('User Identifier'),
+  ).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Status')).not.toBeInTheDocument();
+});
+
+test('Should filter saved expressions by column_name and verbose_name', async 
() => {
+  const { container } = renderPopover({
+    columns: [
+      {
+        column_name: 'calc_revenue',
+        verbose_name: 'Total Sales',
+        expression: 'price * quantity',
+      },
+      {
+        column_name: 'calc_tax',
+        verbose_name: 'Tax Amount',
+        expression: 'price * 0.1',
+      },
+      {
+        column_name: 'calc_profit',
+        verbose_name: 'Net Profit',
+        expression: 'revenue - cost',
+      },
+      {
+        column_name: 'calc_margin',
+        verbose_name: 'Profit Margin',
+        expression: 'profit / revenue',
+      },
+      {
+        column_name: 'calc_discount',
+        verbose_name: 'Discount Rate',
+        expression: 'discount / price',
+      },
+    ],
+    editedColumn: undefined,
+    getCurrentTab: jest.fn(),
+    onChange: jest.fn(),
+  });
+
+  const savedTab = 
container.querySelector('#adhoc-metric-edit-tabs-tab-saved');
+  expect(savedTab).not.toBeNull();
+  fireEvent.click(savedTab!);
+
+  const combobox = screen.getByRole('combobox', {
+    name: 'Saved expressions',
+  });
+
+  await userEvent.type(combobox, 'revenue');
+
+  let dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Total Sales')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Tax Amount')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Net Profit')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Profit 
Margin')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Discount 
Rate')).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, 'Rate');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Discount Rate')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Sales')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Tax Amount')).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, 'profit');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Net Profit')).toBeInTheDocument();
+  expect(within(dropdown).getByText('Profit Margin')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Sales')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Tax Amount')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Discount 
Rate')).not.toBeInTheDocument();
+});
diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index 4a9ccd63269..e2246533535 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -427,8 +427,12 @@ const ColumnSelectPopover = ({
                                   />
                                 ),
                                 key: calculatedColumn.column_name,
+                                column_name: calculatedColumn.column_name,
+                                verbose_name:
+                                  calculatedColumn.verbose_name ?? '',
                               }),
                             )}
+                            optionFilterProps={['column_name', 'verbose_name']}
                           />
                         </FormItem>
                       ) : datasourceType === DatasourceType.Table ? (
@@ -544,6 +548,8 @@ const ColumnSelectPopover = ({
                             />
                           ),
                           key: `column-${simpleColumn.column_name}`,
+                          column_name: simpleColumn.column_name,
+                          verbose_name: simpleColumn.verbose_name ?? '',
                         })),
                         ...availableMetrics.map(metric => ({
                           value: metric.metric_name,
@@ -556,8 +562,15 @@ const ColumnSelectPopover = ({
                             </MetricOptionContainer>
                           ),
                           key: `metric-${metric.metric_name}`,
+                          metric_name: metric.metric_name,
+                          verbose_name: metric.verbose_name ?? '',
                         })),
                       ]}
+                      optionFilterProps={[
+                        'column_name',
+                        'verbose_name',
+                        'metric_name',
+                      ]}
                     />
                   </FormItem>
                 )}
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx
index 81b3649be44..a18346ffa0f 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx
@@ -21,6 +21,7 @@ import {
   screen,
   selectOption,
   userEvent,
+  within,
 } from 'spec/helpers/testing-library';
 import AdhocMetric from 
'src/explore/components/controls/MetricControl/AdhocMetric';
 import AdhocMetricEditPopover from '.';
@@ -248,3 +249,160 @@ test('Should render "Custom SQL" tab correctly', async () 
=> {
 
   expect(await screen.findByRole('textbox')).toBeInTheDocument();
 });
+
+test('Should filter saved metrics by metric_name and verbose_name', async () 
=> {
+  const props = {
+    ...createProps(),
+    savedMetricsOptions: [
+      {
+        id: 1,
+        metric_name: 'count',
+        expression: 'COUNT(*)',
+        verbose_name: 'Total Count',
+      },
+      {
+        id: 2,
+        metric_name: 'revenue_sum',
+        expression: 'sum(revenue)',
+        verbose_name: 'Gross Revenue',
+      },
+      {
+        id: 3,
+        metric_name: 'avg_price',
+        expression: 'AVG(price)',
+        verbose_name: 'Average Price',
+      },
+      {
+        id: 4,
+        metric_name: 'user_count',
+        expression: 'COUNT(DISTINCT user_id)',
+        verbose_name: 'Unique Users',
+      },
+      {
+        id: 5,
+        metric_name: 'total_quantity',
+        expression: 'SUM(quantity)',
+        verbose_name: 'Total Quantity',
+      },
+    ],
+  };
+  render(<AdhocMetricEditPopover {...props} />);
+
+  const combobox = screen.getByRole('combobox', {
+    name: 'Select saved metrics',
+  });
+  userEvent.click(combobox);
+
+  await userEvent.type(combobox, 'revenue');
+
+  let dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Gross Revenue')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Count')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Average 
Price')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Unique Users')).not.toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('Total Quantity'),
+  ).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, 'Unique');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Unique Users')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Total Count')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Gross 
Revenue')).not.toBeInTheDocument();
+
+  await userEvent.clear(combobox);
+  await userEvent.type(combobox, 'total');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Total Count')).toBeInTheDocument();
+  expect(within(dropdown).getByText('Total Quantity')).toBeInTheDocument();
+  expect(within(dropdown).queryByText('Gross 
Revenue')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Average 
Price')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Unique Users')).not.toBeInTheDocument();
+});
+
+test('Should filter columns by column_name and verbose_name in Simple tab', 
async () => {
+  const props = {
+    ...createProps(),
+    columns: [
+      {
+        id: 1,
+        column_name: 'user_id',
+        verbose_name: 'User Identifier',
+        type: 'INTEGER',
+      },
+      {
+        id: 2,
+        column_name: 'created_at',
+        verbose_name: 'Creation Timestamp',
+        type: 'DATETIME',
+      },
+      {
+        id: 3,
+        column_name: 'order_total',
+        verbose_name: 'Order Amount',
+        type: 'DECIMAL',
+      },
+      {
+        id: 4,
+        column_name: 'product_name',
+        verbose_name: 'Product Title',
+        type: 'STRING',
+      },
+      {
+        id: 5,
+        column_name: 'updated_at',
+        verbose_name: 'Last Modified',
+        type: 'DATETIME',
+      },
+    ],
+  };
+  props.getCurrentTab.mockImplementation(tab => {
+    props.adhocMetric.expressionType = tab;
+  });
+  render(<AdhocMetricEditPopover {...props} />);
+
+  const tab = screen.getByRole('tab', { name: 'Simple' }).parentElement!;
+  userEvent.click(tab);
+
+  const columnCombobox = screen.getByRole('combobox', {
+    name: 'Select column',
+  });
+
+  await userEvent.type(columnCombobox, 'product');
+
+  let dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Product Title')).toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('User Identifier'),
+  ).not.toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('Creation Timestamp'),
+  ).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Order Amount')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Last 
Modified')).not.toBeInTheDocument();
+
+  await userEvent.clear(columnCombobox);
+  await userEvent.type(columnCombobox, 'Modified');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Last Modified')).toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('User Identifier'),
+  ).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Product 
Title')).not.toBeInTheDocument();
+
+  await userEvent.clear(columnCombobox);
+  await userEvent.type(columnCombobox, '_at');
+
+  dropdown = document.querySelector('.rc-virtual-list') as HTMLElement;
+  expect(within(dropdown).getByText('Creation Timestamp')).toBeInTheDocument();
+  expect(within(dropdown).getByText('Last Modified')).toBeInTheDocument();
+  expect(
+    within(dropdown).queryByText('User Identifier'),
+  ).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Order Amount')).not.toBeInTheDocument();
+  expect(within(dropdown).queryByText('Product 
Title')).not.toBeInTheDocument();
+});
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
index fc90dbf4eb0..0eaa5b23b09 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
@@ -450,8 +450,11 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
                           value: savedMetric.metric_name,
                           label: this.renderMetricOption(savedMetric),
                           key: savedMetric.id,
+                          metric_name: savedMetric.metric_name,
+                          verbose_name: savedMetric.verbose_name ?? '',
                         }),
                       )}
+                      optionFilterProps={['metric_name', 'verbose_name']}
                       {...savedSelectProps}
                     />
                   </FormItem>
@@ -509,7 +512,10 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
                         value: column.column_name,
                         key: (column as { id?: unknown }).id,
                         label: this.renderColumnOption(column),
+                        column_name: column.column_name,
+                        verbose_name: column.verbose_name ?? '',
                       }))}
+                      optionFilterProps={['column_name', 'verbose_name']}
                       {...columnSelectProps}
                     />
                   </FormItem>

Reply via email to