diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/controlPanel.tsx index dc3397bf774..292672d73cb 100644 --- a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/controlPanel.tsx @@ -281,11 +281,7 @@ const config: ControlPanelConfig = { { controls, datasource, form_data }: ControlPanelState, controlState: ControlState, ) => ({ - columns: datasource?.columns[0]?.hasOwnProperty('filterable') - ? (datasource as Dataset)?.columns?.filter( - (c: ColumnMeta) => c.filterable, - ) - : datasource?.columns, + columns: datasource?.columns || [], savedMetrics: defineSavedMetrics(datasource), // current active adhoc metrics selectedMetrics: diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/test/controlPanel.test.tsx b/superset-frontend/plugins/plugin-chart-ag-grid-table/test/controlPanel.test.tsx index b85535d5340..68c34b5f98e 100644 --- a/superset-frontend/plugins/plugin-chart-ag-grid-table/test/controlPanel.test.tsx +++ b/superset-frontend/plugins/plugin-chart-ag-grid-table/test/controlPanel.test.tsx @@ -19,6 +19,7 @@ import { GenericDataType } from '@apache-superset/core/common'; import { QueryFormData } from '@superset-ui/core'; import { + ColumnMeta, Dataset, isCustomControlItem, ControlConfig, @@ -45,6 +46,32 @@ const findConditionalFormattingControl = (): ControlConfig | null => { return null; }; +const findMetricsMapStateToProps = (): + | ControlConfig['mapStateToProps'] + | null => { + for (const section of config.controlPanelSections) { + if (!section) continue; + for (const row of section.controlSetRows) { + for (const control of row) { + if ( + control && + typeof control === 'object' && + 'name' in control && + (control as { name: string }).name === 'metrics' && + 'override' in control + ) { + return ( + control as { + override: { mapStateToProps: ControlConfig['mapStateToProps'] }; + } + ).override.mapStateToProps; + } + } + } + } + return null; +}; + const createMockControlState = (value: string[] | undefined): ControlState => ({ type: 'SelectControl', value, @@ -206,3 +233,47 @@ test('static extraColorChoices removed from config', () => { expect(controlConfig?.extraColorChoices).toBeUndefined(); }); + +const createMockExploreWithColumns = ( + columns: Partial[], +): ControlPanelState => ({ + slice: { slice_id: 123 }, + datasource: { + verbose_map: {}, + columns, + metrics: [], + } as Partial as Dataset, + controls: {}, + form_data: { + datasource: 'test', + viz_type: 'table', + } as QueryFormData, + common: {}, + metadata: {}, +}); + +const createMockMetricsControlState = (): ControlState => ({ + type: 'MetricsControl', + value: [], + label: '', + default: undefined, + renderTrigger: false, +}); + +test('metrics control includes non-filterable columns', () => { + const mapStateToProps = findMetricsMapStateToProps(); + expect(mapStateToProps).toBeTruthy(); + + const explore = createMockExploreWithColumns([ + { column_name: 'filterable_col', filterable: true }, + { column_name: 'non_filterable_col', filterable: false }, + ]); + const result = mapStateToProps!(explore, createMockMetricsControlState()); + + expect(result.columns).toEqual( + expect.arrayContaining([ + expect.objectContaining({ column_name: 'filterable_col' }), + expect.objectContaining({ column_name: 'non_filterable_col' }), + ]), + ); +}); diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx index bd7d30a139f..5b234d6be63 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/columns.tsx @@ -20,8 +20,6 @@ import { ControlSetItem, ExtraControlProps, sharedControls, - Dataset, - ColumnMeta, } from '@superset-ui/chart-controls'; import { t } from '@apache-superset/core/translation'; import { ensureIsArray } from '@superset-ui/core'; @@ -35,11 +33,7 @@ const dndAllColumns: typeof sharedControls.groupby = { mapStateToProps({ datasource, controls }, controlState) { const newState: ExtraControlProps = {}; if (datasource) { - if (datasource?.columns[0]?.hasOwnProperty('filterable')) { - newState.options = (datasource as Dataset)?.columns?.filter( - (c: ColumnMeta) => c.filterable, - ); - } else newState.options = datasource.columns; + newState.options = datasource.columns || []; } newState.queryMode = getQueryMode(controls); newState.externalValidationErrors = diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx index de33013527b..7eeecd4d240 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/metrics.tsx @@ -21,8 +21,6 @@ import { ControlSetItem, ControlState, sharedControls, - Dataset, - ColumnMeta, defineSavedMetrics, } from '@superset-ui/chart-controls'; import { t } from '@apache-superset/core/translation'; @@ -77,11 +75,7 @@ export const metricsControlSetItem: ControlSetItem = { { controls, datasource, form_data }: ControlPanelState, controlState: ControlState, ) => ({ - columns: datasource?.columns[0]?.hasOwnProperty('filterable') - ? (datasource as Dataset)?.columns?.filter( - (c: ColumnMeta) => c.filterable, - ) - : datasource?.columns, + columns: datasource?.columns || [], savedMetrics: defineSavedMetrics(datasource), // current active adhoc metrics selectedMetrics: diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index 814d82f9d45..2801f1478e0 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -304,11 +304,7 @@ const config: ControlPanelConfig = { { controls, datasource, form_data }: ControlPanelState, controlState: ControlState, ) => ({ - columns: datasource?.columns[0]?.hasOwnProperty('filterable') - ? (datasource as Dataset)?.columns?.filter( - (c: ColumnMeta) => c.filterable, - ) - : datasource?.columns, + columns: datasource?.columns || [], savedMetrics: defineSavedMetrics(datasource), // current active adhoc metrics selectedMetrics: diff --git a/superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx b/superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx index 9a35494e78a..9c45037683f 100644 --- a/superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx +++ b/superset-frontend/plugins/plugin-chart-table/test/controlPanel.test.tsx @@ -19,6 +19,7 @@ import { GenericDataType } from '@apache-superset/core/common'; import { QueryFormData } from '@superset-ui/core'; import { + ColumnMeta, Dataset, isCustomControlItem, ControlConfig, @@ -46,6 +47,32 @@ const findConditionalFormattingControl = (): ControlConfig | null => { return null; }; +const findMetricsMapStateToProps = (): + | ControlConfig['mapStateToProps'] + | null => { + for (const section of config.controlPanelSections) { + if (!section) continue; + for (const row of section.controlSetRows) { + for (const control of row) { + if ( + control && + typeof control === 'object' && + 'name' in control && + (control as { name: string }).name === 'metrics' && + 'override' in control + ) { + return ( + control as { + override: { mapStateToProps: ControlConfig['mapStateToProps'] }; + } + ).override.mapStateToProps; + } + } + } + } + return null; +}; + const createMockControlState = (value: string[] | undefined): ControlState => ({ type: 'SelectControl', value, @@ -209,6 +236,50 @@ test('static extraColorChoices removed from config', () => { expect(controlConfig?.extraColorChoices).toBeUndefined(); }); +const createMockExploreWithColumns = ( + columns: Partial[], +): ControlPanelState => ({ + slice: { slice_id: 123 }, + datasource: { + verbose_map: {}, + columns, + metrics: [], + } as Partial as Dataset, + controls: {}, + form_data: { + datasource: 'test', + viz_type: 'table', + } as QueryFormData, + common: {}, + metadata: {}, +}); + +const createMockMetricsControlState = (): ControlState => ({ + type: 'MetricsControl', + value: [], + label: '', + default: undefined, + renderTrigger: false, +}); + +test('metrics control includes non-filterable columns', () => { + const mapStateToProps = findMetricsMapStateToProps(); + expect(mapStateToProps).toBeTruthy(); + + const explore = createMockExploreWithColumns([ + { column_name: 'filterable_col', filterable: true }, + { column_name: 'non_filterable_col', filterable: false }, + ]); + const result = mapStateToProps!(explore, createMockMetricsControlState()); + + expect(result.columns).toEqual( + expect.arrayContaining([ + expect.objectContaining({ column_name: 'filterable_col' }), + expect.objectContaining({ column_name: 'non_filterable_col' }), + ]), + ); +}); + test('columnOptions falls back to datasource columns when queriesResponse is empty', () => { const controlConfig = findConditionalFormattingControl(); expect(controlConfig).toBeTruthy();