This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch chore/lint-cleanup-tech-debt-2 in repository https://gitbox.apache.org/repos/asf/superset.git
commit 2c36133ed1268a0fa36d1641248a44ab68313ac2 Author: Evan Rusackas <[email protected]> AuthorDate: Wed Feb 11 00:10:40 2026 -0800 chore(lint): enforce more strict eslint/oxlint rules (batch 2) Upgrade more lint rules from warn to error: - unicorn/no-useless-length-check - no-constant-binary-expression - no-unsafe-optional-chaining Add new rules: - storybook/prefer-pascal-case - react-you-might-not-need-an-effect/no-reset-all-state-on-prop-change - react-you-might-not-need-an-effect/no-chain-state-updates - react-you-might-not-need-an-effect/no-event-handler - react-you-might-not-need-an-effect/no-derived-state Fix violations: - state.ts: Remove redundant array length checks (every() handles empty arrays) - buildQuery.ts: Move nullish coalescing inside Number() call - Modal.tsx: Remove unnecessary optional chaining on document.documentElement - Layout.test.tsx: Extract boolean to variable to avoid constant expression - transformProps.test.ts: Use non-null assertion instead of optional chaining Co-Authored-By: Claude Opus 4.5 <[email protected]> --- superset-frontend/.eslintrc.js | 10 ++++++++++ superset-frontend/oxlint.json | 4 +++- .../src/components/Layout/Layout.test.tsx | 6 ++++-- .../superset-ui-core/src/components/Modal/Modal.tsx | 2 +- .../plugins/plugin-chart-ag-grid-table/src/buildQuery.ts | 2 +- .../test/BigNumber/transformProps.test.ts | 16 ++++++++++++---- .../plugins/plugin-chart-table/src/buildQuery.ts | 2 +- .../src/dashboard/components/nativeFilters/state.ts | 10 ++++------ 8 files changed, 36 insertions(+), 16 deletions(-) diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js index 5f4b50ff9d2..53a5b91670b 100644 --- a/superset-frontend/.eslintrc.js +++ b/superset-frontend/.eslintrc.js @@ -135,6 +135,7 @@ module.exports = { 'icons', 'i18n-strings', 'react-prefer-function-component', + 'react-you-might-not-need-an-effect', 'prettier', ], rules: { @@ -238,6 +239,15 @@ 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 81b7523dce5..980587090e4 100644 --- a/superset-frontend/oxlint.json +++ b/superset-frontend/oxlint.json @@ -33,7 +33,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", @@ -250,6 +251,7 @@ ], // === Unicorn rules (bonus coverage) === + "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..12784689afa 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( <Layout> - {false && <Layout.Header>Header</Layout.Header>} + {headerVisible && <Layout.Header>Header</Layout.Header>} <Layout.Content>Content Area</Layout.Content> <Layout.Footer>Ant Design Layout Footer</Layout.Footer> </Layout>, @@ -59,11 +60,12 @@ describe('Layout Component', () => { }); test('hides Footer when footerVisible is false', () => { + const footerVisible = false; render( <Layout> <Layout.Header>Header</Layout.Header> <Layout.Content>Content Area</Layout.Content> - {false && <Layout.Footer>Ant Design Layout Footer</Layout.Footer>} + {footerVisible && <Layout.Footer>Ant Design Layout Footer</Layout.Footer>} </Layout>, ); 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<TableChartFormData> = ( { ...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<TableChartFormData> = ( { ...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)) ); });
