From 6b80135aa283ee15a1439e69c762e617c990383c Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Wed, 18 Feb 2026 22:27:27 -0500 Subject: [PATCH] chore(lint): enforce more strict eslint/oxlint rules (batch 2) (#37884) Co-authored-by: Claude Opus 4.5 --- superset-frontend/.eslintrc.js | 10 ++++++++++ superset-frontend/oxlint.json | 4 +++- .../src/components/Layout/Layout.test.tsx | 8 ++++++-- .../src/components/Modal/Modal.tsx | 2 +- .../plugin-chart-ag-grid-table/src/buildQuery.ts | 2 +- .../test/BigNumber/transformProps.test.ts | 16 ++++++++++++---- .../plugins/plugin-chart-table/src/buildQuery.ts | 2 +- .../dashboard/components/nativeFilters/state.ts | 10 ++++------ 8 files changed, 38 insertions(+), 16 deletions(-) diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js index a2c9b3ae5d7..bf6cb9b6fd6 100644 --- a/superset-frontend/.eslintrc.js +++ b/superset-frontend/.eslintrc.js @@ -245,6 +245,16 @@ module.exports = { // Lodash 'lodash/import-scope': [2, 'member'], + // React effect best practices + 'react-you-might-not-need-an-effect/no-reset-all-state-on-prop-change': + 'error', + 'react-you-might-not-need-an-effect/no-chain-state-updates': 'error', + 'react-you-might-not-need-an-effect/no-event-handler': 'error', + 'react-you-might-not-need-an-effect/no-derived-state': 'error', + + // Storybook + 'storybook/prefer-pascal-case': 'error', + // File progress 'file-progress/activate': 1, diff --git a/superset-frontend/oxlint.json b/superset-frontend/oxlint.json index 50e482ecedd..942965a865d 100644 --- a/superset-frontend/oxlint.json +++ b/superset-frontend/oxlint.json @@ -34,7 +34,8 @@ "no-unused-vars": "off", "no-undef": "error", "no-prototype-builtins": "off", - "no-unsafe-optional-chaining": "off", + "no-unsafe-optional-chaining": "error", + "no-constant-binary-expression": "error", "no-import-assign": "off", "no-promise-executor-return": "off", @@ -254,6 +255,7 @@ // === Unicorn rules (bonus coverage) === "unicorn/no-new-array": "error", "unicorn/no-invalid-remove-event-listener": "error", + "unicorn/no-useless-length-check": "error", "unicorn/filename-case": "off", "unicorn/prevent-abbreviations": "off", "unicorn/no-null": "off", diff --git a/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx index 88a70ff9e6e..0b24bdbc376 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx @@ -47,9 +47,10 @@ describe('Layout Component', () => { }); test('hides Header when headerVisible is false', () => { + const headerVisible = false; render( - {false && Header} + {headerVisible && Header} Content Area Ant Design Layout Footer , @@ -59,11 +60,14 @@ describe('Layout Component', () => { }); test('hides Footer when footerVisible is false', () => { + const footerVisible = false; render( Header Content Area - {false && Ant Design Layout Footer} + {footerVisible && ( + Ant Design Layout Footer + )} , ); diff --git a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx index 021341808e0..173ab6f83a2 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx @@ -280,7 +280,7 @@ const CustomModal = ({ const shouldShowMask = !(resizable || draggable); const onDragStart = (_: DraggableEvent, uiData: DraggableData) => { - const { clientWidth, clientHeight } = window?.document?.documentElement; + const { clientWidth, clientHeight } = document.documentElement; const targetRect = draggableRef?.current?.getBoundingClientRect(); if (targetRect) { diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts index 9212936686b..8122c86f825 100644 --- a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts @@ -606,7 +606,7 @@ const buildQuery: BuildQuery = ( { ...queryObject, time_offsets: [], - row_limit: Number(formData?.row_limit) ?? 0, + row_limit: Number(formData?.row_limit ?? 0), row_offset: 0, post_processing: [], is_rowcount: true, diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts index 3c681f281b0..66933c4f813 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts @@ -196,7 +196,9 @@ describe('BigNumberWithTrendline', () => { showXAxis: true, }, }); - expect((transformed.echartOptions?.xAxis as any).show).toBe(true); + expect((transformed.echartOptions!.xAxis as { show: boolean }).show).toBe( + true, + ); }); test('should not show X axis when showXAxis is false', () => { @@ -207,7 +209,9 @@ describe('BigNumberWithTrendline', () => { showXAxis: false, }, }); - expect((transformed.echartOptions?.xAxis as any).show).toBe(false); + expect((transformed.echartOptions!.xAxis as { show: boolean }).show).toBe( + false, + ); }); test('should show Y axis when showYAxis is true', () => { @@ -218,7 +222,9 @@ describe('BigNumberWithTrendline', () => { showYAxis: true, }, }); - expect((transformed.echartOptions?.yAxis as any).show).toBe(true); + expect((transformed.echartOptions!.yAxis as { show: boolean }).show).toBe( + true, + ); }); test('should not show Y axis when showYAxis is false', () => { @@ -229,7 +235,9 @@ describe('BigNumberWithTrendline', () => { showYAxis: false, }, }); - expect((transformed.echartOptions?.yAxis as any).show).toBe(false); + expect((transformed.echartOptions!.yAxis as { show: boolean }).show).toBe( + false, + ); }); }); diff --git a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts index 7b3a952d891..c23a8a49c56 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts @@ -347,7 +347,7 @@ const buildQuery: BuildQuery = ( { ...queryObject, time_offsets: [], - row_limit: Number(formData?.row_limit) ?? 0, + row_limit: Number(formData?.row_limit ?? 0), row_offset: 0, post_processing: [], is_rowcount: true, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/state.ts index f95c1bae4ef..ecbb56e47a0 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/state.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/state.ts @@ -210,10 +210,9 @@ export function useIsFilterInScope() { if (hasChartsInScope) { isChartInScope = filter.chartsInScope!.some((chartId: number) => { const tabParents = selectChartTabParents(chartId); + // Note: every() returns true for empty arrays, so length check is unnecessary return ( - !tabParents || - tabParents.length === 0 || - tabParents.every(tab => activeTabs.includes(tab)) + !tabParents || tabParents.every(tab => activeTabs.includes(tab)) ); }); } @@ -276,10 +275,9 @@ export function useIsCustomizationInScope() { customization.chartsInScope.length > 0 && customization.chartsInScope.some((chartId: number) => { const tabParents = selectChartTabParents(chartId); + // Note: every() returns true for empty arrays, so length check is unnecessary return ( - !tabParents || - tabParents.length === 0 || - tabParents.every(tab => activeTabs.includes(tab)) + !tabParents || tabParents.every(tab => activeTabs.includes(tab)) ); });