From a3aef764275440b293f560a500c9515ffa35041d Mon Sep 17 00:00:00 2001 From: Gabriel Torres Ruiz Date: Wed, 22 Oct 2025 21:39:00 -0400 Subject: [PATCH] fix(ag-grid): fix conditional formatting theme colors and module extensibility (#35605) (cherry picked from commit 5e4a80e5d02e3e362b120c52688e8ad8dee0ee19) --- .../src/utils/getColorFormatters.ts | 13 +- .../ThemedAgGridReact.test.tsx | 26 ++++ .../components/ThemedAgGridReact/index.tsx | 4 +- .../setupAGGridModules.test.ts | 116 ++++++++++++++++++ .../ThemedAgGridReact/setupAGGridModules.ts | 47 +++---- .../superset-ui-core/src/components/index.ts | 1 + .../src/images/thumbnail-dark.png | Bin 0 -> 52566 bytes .../src/transformProps.ts | 95 +++++++------- .../BigNumberTotal/transformProps.ts | 3 +- .../src/plugin/transformProps.ts | 7 +- .../plugin-chart-table/src/transformProps.ts | 3 +- .../ColumnConfigControl/ColumnConfigItem.tsx | 2 +- .../FormattingPopoverContent.tsx | 14 +-- 13 files changed, 249 insertions(+), 82 deletions(-) create mode 100644 superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.test.ts create mode 100644 superset-frontend/plugins/plugin-chart-ag-grid-table/src/images/thumbnail-dark.png diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts index 4e5e89fe411..f1e37d789d1 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts @@ -191,10 +191,21 @@ export const getColorFormatters = memoizeOne( ( columnConfig: ConditionalFormattingConfig[] | undefined, data: DataRecord[], + theme?: Record, alpha?: boolean, ) => columnConfig?.reduce( (acc: ColorFormatters, config: ConditionalFormattingConfig) => { + let resolvedColorScheme = config.colorScheme; + if ( + theme && + typeof config.colorScheme === 'string' && + config.colorScheme.startsWith('color') && + theme[config.colorScheme] + ) { + resolvedColorScheme = theme[config.colorScheme] as string; + } + if ( config?.column !== undefined && (config?.operator === Comparator.None || @@ -207,7 +218,7 @@ export const getColorFormatters = memoizeOne( acc.push({ column: config?.column, getColorFromValue: getColorFunction( - config, + { ...config, colorScheme: resolvedColorScheme }, data.map(row => row[config.column!] as number), alpha, ), diff --git a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/ThemedAgGridReact.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/ThemedAgGridReact.test.tsx index 9620659d78d..e534f920e5e 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/ThemedAgGridReact.test.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/ThemedAgGridReact.test.tsx @@ -218,3 +218,29 @@ test('handles missing theme gracefully', () => { // Should still render without crashing expect(screen.getByTestId('ag-grid-react')).toBeInTheDocument(); }); + +test('merges theme overrides with default theme parameters', () => { + const themeOverrides = { + fontSize: 16, + headerBackgroundColor: '#custom-color', + }; + + render( + , + ); + + const agGrid = screen.getByTestId('ag-grid-react'); + const theme = JSON.parse(agGrid.getAttribute('data-theme') || '{}'); + + // Custom overrides should be applied + expect(theme.fontSize).toBe(16); + expect(theme.headerBackgroundColor).toBe('#custom-color'); + + // Default theme parameters should still be present + expect(theme.foregroundColor).toBeDefined(); + expect(theme.borderColor).toBeDefined(); +}); diff --git a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/index.tsx b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/index.tsx index 5e95a9c0002..da3fc8c5910 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/index.tsx @@ -186,5 +186,5 @@ export { // Re-export AgGridReact for ref types export { AgGridReact } from 'ag-grid-react'; -// Export the setup function for AG-Grid modules -export { setupAGGridModules } from './setupAGGridModules'; +// Export the setup function and default modules for AG-Grid +export { setupAGGridModules, defaultModules } from './setupAGGridModules'; diff --git a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.test.ts b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.test.ts new file mode 100644 index 00000000000..f64fe023107 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.test.ts @@ -0,0 +1,116 @@ +/** + * 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 { ModuleRegistry, type Module } from 'ag-grid-community'; +import { setupAGGridModules, defaultModules } from './setupAGGridModules'; + +jest.mock('ag-grid-community', () => ({ + ModuleRegistry: { + registerModules: jest.fn(), + }, + ColumnAutoSizeModule: { moduleName: 'ColumnAutoSizeModule' }, + ColumnHoverModule: { moduleName: 'ColumnHoverModule' }, + RowAutoHeightModule: { moduleName: 'RowAutoHeightModule' }, + RowStyleModule: { moduleName: 'RowStyleModule' }, + PaginationModule: { moduleName: 'PaginationModule' }, + CellStyleModule: { moduleName: 'CellStyleModule' }, + TextFilterModule: { moduleName: 'TextFilterModule' }, + NumberFilterModule: { moduleName: 'NumberFilterModule' }, + DateFilterModule: { moduleName: 'DateFilterModule' }, + ExternalFilterModule: { moduleName: 'ExternalFilterModule' }, + CsvExportModule: { moduleName: 'CsvExportModule' }, + ColumnApiModule: { moduleName: 'ColumnApiModule' }, + RowApiModule: { moduleName: 'RowApiModule' }, + CellApiModule: { moduleName: 'CellApiModule' }, + RenderApiModule: { moduleName: 'RenderApiModule' }, + ClientSideRowModelModule: { moduleName: 'ClientSideRowModelModule' }, + CustomFilterModule: { moduleName: 'CustomFilterModule' }, +})); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +test('defaultModules exports an array of AG Grid modules', () => { + expect(Array.isArray(defaultModules)).toBe(true); + expect(defaultModules.length).toBeGreaterThan(0); + + // Verify it contains expected modules + const moduleNames = defaultModules.map((m: any) => m.moduleName); + expect(moduleNames).toContain('ColumnAutoSizeModule'); + expect(moduleNames).toContain('PaginationModule'); + expect(moduleNames).toContain('ClientSideRowModelModule'); +}); + +test('setupAGGridModules registers default modules when called without arguments', () => { + setupAGGridModules(); + + expect(ModuleRegistry.registerModules).toHaveBeenCalledTimes(1); + expect(ModuleRegistry.registerModules).toHaveBeenCalledWith(defaultModules); +}); + +test('setupAGGridModules registers default + additional modules when provided', () => { + const mockEnterpriseModule1 = { + moduleName: 'MultiFilterModule', + } as unknown as Module; + const mockEnterpriseModule2 = { + moduleName: 'PivotModule', + } as unknown as Module; + const additionalModules = [mockEnterpriseModule1, mockEnterpriseModule2]; + + setupAGGridModules(additionalModules); + + expect(ModuleRegistry.registerModules).toHaveBeenCalledTimes(1); + + const registeredModules = (ModuleRegistry.registerModules as jest.Mock).mock + .calls[0][0]; + + // Should contain all default modules + defaultModules.forEach(module => { + expect(registeredModules).toContain(module); + }); + + // Should contain additional modules + expect(registeredModules).toContain(mockEnterpriseModule1); + expect(registeredModules).toContain(mockEnterpriseModule2); + + // Total length should be default + additional + expect(registeredModules.length).toBe( + defaultModules.length + additionalModules.length, + ); +}); + +test('setupAGGridModules handles empty additional modules array', () => { + setupAGGridModules([]); + + expect(ModuleRegistry.registerModules).toHaveBeenCalledTimes(1); + expect(ModuleRegistry.registerModules).toHaveBeenCalledWith(defaultModules); +}); + +test('setupAGGridModules does not mutate defaultModules array', () => { + const originalLength = defaultModules.length; + const mockEnterpriseModule = { + moduleName: 'EnterpriseModule', + } as unknown as Module; + + setupAGGridModules([mockEnterpriseModule]); + + // defaultModules should remain unchanged + expect(defaultModules.length).toBe(originalLength); + expect(defaultModules).not.toContain(mockEnterpriseModule); +}); diff --git a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.ts b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.ts index 6c0cc641915..7bc39fc56db 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.ts +++ b/superset-frontend/packages/superset-ui-core/src/components/ThemedAgGridReact/setupAGGridModules.ts @@ -19,6 +19,7 @@ import { ModuleRegistry, + type Module, ColumnAutoSizeModule, ColumnHoverModule, RowAutoHeightModule, @@ -39,27 +40,29 @@ import { } from 'ag-grid-community'; /** - * Registers the AG-Grid modules required for Superset's table functionality. - * This should be called once during application initialization. + * Default AG Grid modules that are registered by default. + * These modules provide core AG Grid functionality. */ -export const setupAGGridModules = () => { - ModuleRegistry.registerModules([ - ColumnAutoSizeModule, - ColumnHoverModule, - RowAutoHeightModule, - RowStyleModule, - PaginationModule, - CellStyleModule, - TextFilterModule, - NumberFilterModule, - DateFilterModule, - ExternalFilterModule, - CsvExportModule, - ColumnApiModule, - RowApiModule, - CellApiModule, - RenderApiModule, - ClientSideRowModelModule, - CustomFilterModule, - ]); +export const defaultModules: Module[] = [ + ColumnAutoSizeModule, + ColumnHoverModule, + RowAutoHeightModule, + RowStyleModule, + PaginationModule, + CellStyleModule, + TextFilterModule, + NumberFilterModule, + DateFilterModule, + ExternalFilterModule, + CsvExportModule, + ColumnApiModule, + RowApiModule, + CellApiModule, + RenderApiModule, + ClientSideRowModelModule, + CustomFilterModule, +]; + +export const setupAGGridModules = (additionalModules: Module[] = []) => { + ModuleRegistry.registerModules([...defaultModules, ...additionalModules]); }; diff --git a/superset-frontend/packages/superset-ui-core/src/components/index.ts b/superset-frontend/packages/superset-ui-core/src/components/index.ts index 1aea7e70bd5..9aa450e03b9 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/components/index.ts @@ -179,4 +179,5 @@ export { ThemedAgGridReact, type ThemedAgGridReactProps, setupAGGridModules, + defaultModules, } from './ThemedAgGridReact'; diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/images/thumbnail-dark.png b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/images/thumbnail-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..919eaa2118eac42e74119ab7570162e5d4cad1ca GIT binary patch literal 52566 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 literal 0 HcmV?d00001 diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/transformProps.ts b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/transformProps.ts index b59567fa8ef..1f288de54af 100644 --- a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/transformProps.ts @@ -75,6 +75,23 @@ function isPositiveNumber(value: string | number | null | undefined) { ); } +const calculateDifferences = ( + originalValue: number, + comparisonValue: number, +) => { + const valueDifference = originalValue - comparisonValue; + let percentDifferenceNum; + if (!originalValue && !comparisonValue) { + percentDifferenceNum = 0; + } else if (!originalValue || !comparisonValue) { + percentDifferenceNum = originalValue ? 1 : -1; + } else { + percentDifferenceNum = + (originalValue - comparisonValue) / Math.abs(comparisonValue); + } + return { valueDifference, percentDifferenceNum }; +}; + const processComparisonTotals = ( comparisonSuffix: string, totals?: DataRecord[], @@ -150,23 +167,6 @@ const getComparisonColFormatter = ( return formatter; }; -const calculateDifferences = ( - originalValue: number, - comparisonValue: number, -) => { - const valueDifference = originalValue - comparisonValue; - let percentDifferenceNum; - if (!originalValue && !comparisonValue) { - percentDifferenceNum = 0; - } else if (!originalValue || !comparisonValue) { - percentDifferenceNum = originalValue ? 1 : -1; - } else { - percentDifferenceNum = - (originalValue - comparisonValue) / Math.abs(comparisonValue); - } - return { valueDifference, percentDifferenceNum }; -}; - const processComparisonDataRecords = memoizeOne( function processComparisonDataRecords( originalData: DataRecord[] | undefined, @@ -472,6 +472,7 @@ const transformProps = ( filterState, hooks: { setDataMask = () => {} }, emitCrossFilters, + theme, } = chartProps; const { @@ -495,6 +496,36 @@ const transformProps = ( const allowRearrangeColumns = true; + // Calculate time comparison settings early since they're used in multiple places + const isUsingTimeComparison = + !isEmpty(time_compare) && + queryMode === QueryMode.Aggregate && + comparison_type === ComparisonType.Values && + isFeatureEnabled(FeatureFlag.TableV2TimeComparisonEnabled); + + const nonCustomNorInheritShifts = ensureIsArray(formData.time_compare).filter( + (shift: string) => shift !== 'custom' && shift !== 'inherit', + ); + const customOrInheritShifts = ensureIsArray(formData.time_compare).filter( + (shift: string) => shift === 'custom' || shift === 'inherit', + ); + + let timeOffsets: string[] = []; + + if (isUsingTimeComparison && !isEmpty(nonCustomNorInheritShifts)) { + timeOffsets = nonCustomNorInheritShifts; + } + + // Shifts for custom or inherit time comparison + if (isUsingTimeComparison && !isEmpty(customOrInheritShifts)) { + if (customOrInheritShifts.includes('custom')) { + timeOffsets = timeOffsets.concat([formData.start_date_offset]); + } + if (customOrInheritShifts.includes('inherit')) { + timeOffsets = timeOffsets.concat(['inherit']); + } + } + const calculateBasicStyle = ( percentDifferenceNum: number, colorOption: ColorSchemeEnum, @@ -607,12 +638,6 @@ const transformProps = ( : undefined; }; - const isUsingTimeComparison = - !isEmpty(time_compare) && - queryMode === QueryMode.Aggregate && - comparison_type === ComparisonType.Values && - isFeatureEnabled(FeatureFlag.TableV2TimeComparisonEnabled); - let hasServerPageLengthChanged = false; const pageLengthFromMap = serverPageLengthMap.get(slice_id); @@ -625,28 +650,6 @@ const transformProps = ( const timeGrain = extractTimegrain(formData); - const nonCustomNorInheritShifts = ensureIsArray(formData.time_compare).filter( - (shift: string) => shift !== 'custom' && shift !== 'inherit', - ); - const customOrInheritShifts = ensureIsArray(formData.time_compare).filter( - (shift: string) => shift === 'custom' || shift === 'inherit', - ); - - let timeOffsets: string[] = []; - - if (isUsingTimeComparison && !isEmpty(nonCustomNorInheritShifts)) { - timeOffsets = nonCustomNorInheritShifts; - } - - // Shifts for custom or inherit time comparison - if (isUsingTimeComparison && !isEmpty(customOrInheritShifts)) { - if (customOrInheritShifts.includes('custom')) { - timeOffsets = timeOffsets.concat([formData.start_date_offset]); - } - if (customOrInheritShifts.includes('inherit')) { - timeOffsets = timeOffsets.concat(['inherit']); - } - } const comparisonSuffix = isUsingTimeComparison ? ensureIsArray(timeOffsets)[0] : ''; @@ -686,7 +689,7 @@ const transformProps = ( const basicColorFormatters = comparisonColorEnabled && getBasicColorFormatter(baseQuery?.data, columns); const columnColorFormatters = - getColorFormatters(conditionalFormatting, passedData) ?? []; + getColorFormatters(conditionalFormatting, passedData, theme) ?? []; const basicColorColumnFormatters = getBasicColorFormatterForColumn( baseQuery?.data, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts index 5210e237681..44f85ae2a01 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts @@ -43,6 +43,7 @@ export default function transformProps( rawFormData, hooks, datasource: { currencyFormats = {}, columnFormats = {} }, + theme, } = chartProps; const { metricNameFontSize, @@ -105,7 +106,7 @@ export default function transformProps( const defaultColorFormatters = [] as ColorFormatters; const colorThresholdFormatters = - getColorFormatters(conditionalFormatting, data, false) ?? + getColorFormatters(conditionalFormatting, data, theme, false) ?? defaultColorFormatters; return { width, diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts index f6018289804..fab24358971 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts @@ -81,6 +81,7 @@ export default function transformProps(chartProps: ChartProps) { filterState, datasource: { verboseMap = {}, columnFormats = {}, currencyFormats = {} }, emitCrossFilters, + theme, } = chartProps; const { data, colnames, coltypes } = queriesData[0]; const { @@ -141,7 +142,11 @@ export default function transformProps(chartProps: ChartProps) { }, {}, ); - const metricColorFormatters = getColorFormatters(conditionalFormatting, data); + const metricColorFormatters = getColorFormatters( + conditionalFormatting, + data, + theme, + ); return { width, diff --git a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts index 93ff433cb86..23cdde99753 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts @@ -469,6 +469,7 @@ const transformProps = ( onContextMenu, }, emitCrossFilters, + theme, } = chartProps; const formData = merge( @@ -682,7 +683,7 @@ const transformProps = ( const basicColorFormatters = comparisonColorEnabled && getBasicColorFormatter(baseQuery?.data, columns); const columnColorFormatters = - getColorFormatters(conditionalFormatting, passedData) ?? + getColorFormatters(conditionalFormatting, passedData, theme) ?? defaultColorFormatters; const basicColorColumnFormatters = getBasicColorFormatterForColumn( diff --git a/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigItem.tsx b/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigItem.tsx index 31ef15f731d..f71d1584d87 100644 --- a/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigItem.tsx +++ b/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigItem.tsx @@ -76,7 +76,7 @@ export default memo(function ColumnConfigItem({ alignItems: 'center', position: 'absolute', right: 3 * sizeUnit, - top: 3 * sizeUnit, + top: 4 * sizeUnit, transform: 'translateY(-50%)', gap: sizeUnit, color: theme.colorTextSecondary, diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx index 5b18ebf14b7..d17a830f18b 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx @@ -17,7 +17,7 @@ * under the License. */ import { useState } from 'react'; -import { styled, SupersetTheme, t, useTheme } from '@superset-ui/core'; +import { styled, t } from '@superset-ui/core'; import { Comparator, MultipleValueComparators, @@ -50,10 +50,11 @@ const JustifyEnd = styled.div` justify-content: flex-end; `; -const colorSchemeOptions = (theme: SupersetTheme) => [ - { value: theme.colorSuccessBg, label: t('success') }, - { value: theme.colorWarningBg, label: t('alert') }, - { value: theme.colorErrorBg, label: t('error') }, +// Use theme token names instead of hex values to support theme switching +const colorSchemeOptions = () => [ + { value: 'colorSuccessBg', label: t('success') }, + { value: 'colorWarningBg', label: t('alert') }, + { value: 'colorErrorBg', label: t('error') }, ]; const operatorOptions = [ @@ -205,8 +206,7 @@ export const FormattingPopoverContent = ({ columns: { label: string; value: string }[]; extraColorChoices?: { label: string; value: string }[]; }) => { - const theme = useTheme(); - const colorScheme = colorSchemeOptions(theme); + const colorScheme = colorSchemeOptions(); const [showOperatorFields, setShowOperatorFields] = useState( config === undefined || (config?.colorScheme !== ColorSchemeEnum.Green &&