chore: Upgrade to React 18 (#38563)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
This commit is contained in:
Mehmet Salih Yavuz
2026-05-04 19:19:36 +03:00
committed by GitHub
parent 28239c18d4
commit 41a22d7918
183 changed files with 5035 additions and 7225 deletions

View File

@@ -33,7 +33,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -34,6 +34,6 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
}
}

View File

@@ -31,7 +31,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -31,7 +31,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -36,6 +36,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
}
}

View File

@@ -32,9 +32,9 @@
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"@testing-library/jest-dom": "*",
"@testing-library/react": "^12.1.5",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"@testing-library/react": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -32,7 +32,7 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -39,6 +39,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@apache-superset/core": "*",
"react": "^17.0.2"
"react": "^18.2.0"
}
}

View File

@@ -43,6 +43,6 @@
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"react": "^17.0.2"
"react": "^18.2.0"
}
}

View File

@@ -39,14 +39,13 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@testing-library/dom": "^8.20.1",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "*",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "*",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "*",
"@types/react": "*",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -247,7 +247,7 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
[serverPagination, debouncedSearch, searchId],
);
const handleColSort = (colId: string, sortDir: string) => {
const handleColSort = (colId: string, sortDir: string | null) => {
const isSortable = shouldSort({
colId,
sortDir,
@@ -301,10 +301,12 @@ const AgGridDataTable: FunctionComponent<AgGridTableProps> = memo(
};
const handleColumnHeaderClick = useCallback(
params => {
(params: { column?: { colId?: string; sort?: string | null } }) => {
const colId = params?.column?.colId;
const sortDir = params?.column?.sort;
handleColSort(colId, sortDir);
if (colId && sortDir !== undefined) {
handleColSort(colId, sortDir);
}
},
[serverPagination, gridInitialState, percentMetrics, onSortChange],
);

View File

@@ -147,7 +147,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
]);
const handleColumnStateChange = useCallback(
agGridState => {
(agGridState: Record<string, unknown>) => {
if (onChartStateChange) {
onChartStateChange(agGridState);
}

View File

@@ -70,5 +70,9 @@ export const TextCellRenderer = (params: CellRendererProps) => {
}
}
return <div>{valueFormatted ?? value}</div>;
return (
<div>
{valueFormatted ?? (value instanceof Date ? value.toISOString() : value)}
</div>
);
};

View File

@@ -43,7 +43,7 @@ export const shouldSort = ({
gridInitialState,
}: {
colId: string;
sortDir: string;
sortDir: string | null;
percentMetrics: string[];
serverPagination: boolean;
gridInitialState: GridState;

View File

@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { GenericDataType } from '@apache-superset/core/common';
import {
supersetTheme,

View File

@@ -47,7 +47,7 @@
"geostyler-wfs-parser": "^3.0.1",
"ol": "^10.8.0",
"polished": "*",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}

View File

@@ -19,7 +19,7 @@
import Layer from 'ol/layer/Layer';
import { FrameState } from 'ol/Map';
import { apply as applyTransform } from 'ol/transform';
import ReactDOM from 'react-dom';
import { createRoot, Root } from 'react-dom/client';
import { SupersetTheme } from '@apache-superset/core/theme';
import { ChartConfig, ChartLayerOptions, ChartSizeValues } from '../types';
import { createChartComponent } from '../util/chartUtil';
@@ -31,7 +31,14 @@ import Loader from '../images/loading.gif';
* Custom OpenLayers layer that displays charts on given locations.
*/
export class ChartLayer extends Layer {
charts: any[] = [];
charts: {
htmlElement: HTMLDivElement;
root: Root;
coordinate: number[];
width: number;
height: number;
feature: any;
}[] = [];
chartConfigs: ChartConfig = {
type: 'FeatureCollection',
@@ -166,7 +173,7 @@ export class ChartLayer extends Layer {
*/
removeAllChartElements() {
this.charts.forEach(chart => {
ReactDOM.unmountComponentAtNode(chart.htmlElement);
chart.root.unmount();
chart.htmlElement.remove();
});
this.charts = [];
@@ -191,10 +198,12 @@ export class ChartLayer extends Layer {
this.theme,
this.locale,
);
ReactDOM.render(chartComponent, container);
const root = createRoot(container);
root.render(chartComponent);
return {
htmlElement: container,
root,
coordinate: getProjectedCoordinateFromPointGeoJson(feature.geometry),
width: chartWidth,
height: chartHeight,
@@ -227,7 +236,7 @@ export class ChartLayer extends Layer {
this.theme,
this.locale,
);
ReactDOM.render(chartComponent, chart.htmlElement);
chart.root.render(chartComponent);
return {
...chart,

View File

@@ -41,6 +41,11 @@ describe('ChartLayer', () => {
chartLayer.charts = [
{
htmlElement: document.createElement('div'),
root: { render: jest.fn(), unmount: jest.fn() } as any,
coordinate: [0, 0],
width: 100,
height: 100,
feature: {},
},
];

View File

@@ -38,7 +38,7 @@
"dayjs": "^1.11.19",
"echarts": "*",
"memoize-one": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -57,7 +57,7 @@ export default function EchartsMixedTimeseries({
);
const getCrossFilterDataMask = useCallback(
(seriesName, seriesIndex) => {
(seriesName: string, seriesIndex: number) => {
const selected: string[] = Object.values(selectedValues || {});
let values: string[];
if (selected.includes(seriesName)) {

View File

@@ -26,7 +26,7 @@ import {
import { useCallback } from 'react';
import Echart from '../components/Echart';
import { NULL_STRING } from '../constants';
import { EventHandlers } from '../types';
import { EventHandlers, TreePathInfo } from '../types';
import { extractTreePathInfo } from './constants';
import { TreemapTransformedProps } from './types';
import { formatSeriesName } from '../utils/series';
@@ -46,7 +46,7 @@ export default function EchartsTreemap({
coltypeMapping,
}: TreemapTransformedProps) {
const getCrossFilterDataMask = useCallback(
(data, treePathInfo) => {
(data: Record<string, unknown>, treePathInfo: TreePathInfo[]) => {
if (data?.children) {
return undefined;
}
@@ -96,7 +96,7 @@ export default function EchartsTreemap({
);
const handleChange = useCallback(
(data, treePathInfo) => {
(data: Record<string, unknown>, treePathInfo: TreePathInfo[]) => {
if (!emitCrossFilters || groupby.length === 0) {
return;
}

View File

@@ -39,9 +39,9 @@
"handlebars": "^4.7.8",
"lodash": "^4.18.1",
"dayjs": "^1.11.19",
"react": "^17.0.2",
"react": "^18.2.0",
"react-ace": "^10.1.0",
"react-dom": "^17.0.2"
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/jest": "^30.0.0",

View File

@@ -45,10 +45,22 @@ const HandlebarsTemplateControl = (
<div>
<ControlHeader>
<div>
{props.label}
{typeof props.label === 'function' ? null : props.label}
<InfoTooltip
iconStyle={{ marginLeft: theme.sizeUnit }}
tooltip={<span>{t('See ')} <a href="https://superset.apache.org/docs/using-superset/handlebars-chart" target="_blank" rel="noopener noreferrer">{t('the Handlebars chart documentation')}</a> {t('for a list of available helpers.')}</span>}
tooltip={
<span>
{t('See ')}{' '}
<a
href="https://superset.apache.org/docs/using-superset/handlebars-chart"
target="_blank"
rel="noopener noreferrer"
>
{t('the Handlebars chart documentation')}
</a>{' '}
{t('for a list of available helpers.')}
</span>
}
/>
</div>
</ControlHeader>

View File

@@ -49,7 +49,7 @@ const StyleControl = (props: CustomControlConfig<StyleCustomControlProps>) => {
<div>
<ControlHeader>
<div>
{props.label}
{typeof props.label === 'function' ? null : props.label}
{htmlSanitization && (
<InfoTooltip
iconStyle={{ marginLeft: theme.sizeUnit }}

View File

@@ -33,8 +33,8 @@
"@superset-ui/core": "*",
"lodash": "^4.18.1",
"prop-types": "*",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@babel/types": "^7.29.0",

View File

@@ -36,8 +36,8 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"react": "^17.0.2 || ^19.0.0",
"react-dom": "^17.0.2 || ^19.0.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -39,15 +39,14 @@
"@apache-superset/core": "*",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@testing-library/dom": "^8.20.1",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "*",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "*",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "*",
"@types/react": "*",
"match-sorter": "^8.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public"

View File

@@ -533,7 +533,12 @@ export default function TableChart<D extends DataRecord = DataRecord>(
// so that cross-filters work on the receiving chart
const resolvedCol = columnLabelToNameMap[col] ?? col;
const val = ensureIsArray(updatedFilters?.[col]);
if (!val.length || val[0] === null || (val[0] instanceof DateWithFormatter && val[0].input === null))
if (
!val.length ||
val[0] === null ||
(val[0] instanceof DateWithFormatter &&
val[0].input === null)
)
return {
col: resolvedCol,
op: 'IS NULL' as const,
@@ -646,24 +651,22 @@ export default function TableChart<D extends DataRecord = DataRecord>(
// DateWithFormatter objects wrap nulls, so we must check both
if (
dataRecordValue == null ||
(dataRecordValue instanceof DateWithFormatter && dataRecordValue.input == null)
(dataRecordValue instanceof DateWithFormatter &&
dataRecordValue.input == null)
) {
drillToDetailFilters.push({
col: col.key,
op: 'IS NULL' as any,
val: null,
});
} else if (col.dataType === GenericDataType.Temporal && timeGrain) {
const startTime =
dataRecordValue instanceof Date
? dataRecordValue
: new Date(dataRecordValue as string | number);
const [rangeStartTime, rangeEndTime] = getTimeRangeFromGranularity(
startTime,
timeGrain,
);
const [rangeStartTime, rangeEndTime] =
getTimeRangeFromGranularity(startTime, timeGrain);
const timeRangeValue = `${rangeStartTime.toISOString()} : ${rangeEndTime.toISOString()}`;
drillToDetailFilters.push({
@@ -696,7 +699,11 @@ export default function TableChart<D extends DataRecord = DataRecord>(
filters: [
{
col: cellPoint.key,
op: (cellPoint.value == null || (cellPoint.value instanceof DateWithFormatter && cellPoint.value.input == null) ? 'IS NULL' : '==') as any,
op: (cellPoint.value == null ||
(cellPoint.value instanceof DateWithFormatter &&
cellPoint.value.input == null)
? 'IS NULL'
: '==') as any,
val: extractTextFromHTML(cellPoint.value),
},
],

View File

@@ -39,7 +39,7 @@
"@superset-ui/core": "*",
"@types/lodash": "*",
"@types/react": "*",
"react": "^17.0.2"
"react": "^18.2.0"
},
"devDependencies": {
"@types/d3-cloud": "^1.2.9"

View File

@@ -67,8 +67,8 @@
"@superset-ui/core": "*",
"dayjs": "^1.11.19",
"mapbox-gl": ">=1.0.0",
"react": "^17.0.2 || ^19.0.0",
"react-dom": "^17.0.2 || ^19.0.0"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"peerDependenciesMeta": {
"mapbox-gl": {

View File

@@ -139,7 +139,8 @@ const CategoricalDeckGLContainer = (props: CategoricalDeckGLContainerProps) => {
const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
const { current } = containerRef;
if (current) {
current.setTooltip(tooltip);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(current as any).setTooltip(tooltip);
}
}, []);

View File

@@ -194,5 +194,5 @@ export const DeckGLContainerStyledWrapper = styled(DeckGLContainer)`
`;
export type DeckGLContainerHandle = typeof DeckGLContainer & {
setTooltip: (tooltip: ReactNode) => void;
setTooltip: (tooltip: TooltipProps['tooltip']) => void;
};

View File

@@ -97,10 +97,10 @@ describe('getAggFunc', () => {
});
describe('commonLayerProps', () => {
const mockSetTooltip = jest.fn();
const mockSetTooltip = jest.fn() as any;
const mockSetTooltipContent = jest.fn(
() => (o: JsonObject) => `Tooltip for ${o}`,
);
) as any;
const mockOnSelect = jest.fn();
test('returns correct props when js_tooltip is provided', () => {