diff --git a/packages/app/eslint.config.mjs b/packages/app/eslint.config.mjs index aa9b4b43aa..768bb048a2 100644 --- a/packages/app/eslint.config.mjs +++ b/packages/app/eslint.config.mjs @@ -122,12 +122,23 @@ export default [ ...nextPlugin.configs.recommended.rules, ...nextPlugin.configs['core-web-vitals'].rules, ...reactHooksPlugin.configs.recommended.rules, - ...eslintReactPlugin.configs.recommended.rules, - // Disable rules from eslint-plugin-react-hooks that have equivalent rules in @eslint-react - ...eslintReactPlugin.configs['disable-conflict-eslint-plugin-react-hooks'].rules, ...eslintReactPlugin.configs['recommended-type-checked'].rules, - 'react-hooks/set-state-in-effect': 'warn', - 'react-hooks/exhaustive-deps': 'error', + '@eslint-react/exhaustive-deps': 'error', + + // @eslint-react version is experimental, we'll use react-hooks/set-state-in-render instead + '@eslint-react/set-state-in-render': 'off', + 'react-hooks/set-state-in-render': 'error', + + // Disable rules from eslint-plugin-react-hooks that have equivalent rules enabled in @eslint-react + 'react-hooks/rules-of-hooks': 'off', + 'react-hooks/static-components': 'off', + 'react-hooks/use-memo': 'off', + 'react-hooks/component-hook-factories': 'off', + 'react-hooks/error-boundaries': 'off', + 'react-hooks/set-state-in-effect': 'off', + 'react-hooks/unsupported-syntax': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hook-form/no-use-watch': 'error', '@eslint-react/no-unstable-default-props': 'error', '@typescript-eslint/ban-ts-comment': 'warn', diff --git a/packages/app/src/DBChartPage.tsx b/packages/app/src/DBChartPage.tsx index b77c760263..82f2e5e26d 100644 --- a/packages/app/src/DBChartPage.tsx +++ b/packages/app/src/DBChartPage.tsx @@ -166,6 +166,7 @@ function AIAssistant({ {opened && ( + // eslint-disable-next-line react-hooks/refs
{ - // eslint-disable-next-line react-hooks/set-state-in-effect setQueriedConfig((config: ChartConfigWithDateRange | undefined) => { if (config == null) { return config; diff --git a/packages/app/src/components/DBHeatmapChart.tsx b/packages/app/src/components/DBHeatmapChart.tsx index 04c35db61d..f548a3b71d 100644 --- a/packages/app/src/components/DBHeatmapChart.tsx +++ b/packages/app/src/components/DBHeatmapChart.tsx @@ -953,7 +953,7 @@ function Heatmap({ }, plugins: [ // legendAsTooltipPlugin() - + // eslint-disable-next-line react-hooks/refs -- mouseInsideRef is read at event time, not during render highlightDataPlugin({ proximity: 20, yFormatter: tickFormatter, diff --git a/packages/app/src/components/DBRowTable.tsx b/packages/app/src/components/DBRowTable.tsx index d8cdc61a85..7278cc7e35 100644 --- a/packages/app/src/components/DBRowTable.tsx +++ b/packages/app/src/components/DBRowTable.tsx @@ -858,7 +858,7 @@ export const RawLogTable = memo( // Conditions not met, clear flag tableSearch.clearShouldScrollToMatch(); } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps }, [ tableSearch.shouldScrollToMatch, tableSearch.currentMatchIndex, @@ -1531,7 +1531,7 @@ function DBSqlRowTableComponent({ if (prevSourceId && prevSourceId !== sourceId) { _onSortingChange(null); } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps }, [sourceId]); // Sync local orderBy state with initialSortBy when it changes diff --git a/packages/app/src/components/DBTable/TableSearchInput.tsx b/packages/app/src/components/DBTable/TableSearchInput.tsx index ab31b587b7..374b1c838e 100644 --- a/packages/app/src/components/DBTable/TableSearchInput.tsx +++ b/packages/app/src/components/DBTable/TableSearchInput.tsx @@ -141,6 +141,7 @@ export const TableSearchInput = ({ // Handle keyboard shortcuts (Cmd+F, Escape) const handleKeyDown = useCallback( + // eslint-disable-next-line react-hooks/preserve-manual-memoization (e: KeyboardEvent) => { // Detect Cmd+F (Mac) or Ctrl+F (Windows/Linux) if ((e.metaKey || e.ctrlKey) && e.key === 'f') { @@ -155,7 +156,7 @@ export const TableSearchInput = ({ handleClose(); } }, - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps [isVisible, handleClose, handleShow], ); diff --git a/packages/app/src/components/SQLEditor/SQLEditor.tsx b/packages/app/src/components/SQLEditor/SQLEditor.tsx index d445a0e442..ba14096106 100644 --- a/packages/app/src/components/SQLEditor/SQLEditor.tsx +++ b/packages/app/src/components/SQLEditor/SQLEditor.tsx @@ -98,7 +98,7 @@ export default function SQLEditor({ minHeight={'100px'} extensions={[ createCodeMirrorStyleTheme(), - + // eslint-disable-next-line react-hooks/refs compartmentRef.current.of( clickhouseSql({ upperCaseKeywords: true, diff --git a/packages/app/src/components/SQLEditor/SQLInlineEditor.tsx b/packages/app/src/components/SQLEditor/SQLInlineEditor.tsx index 94224486bd..9e8dfaff1e 100644 --- a/packages/app/src/components/SQLEditor/SQLInlineEditor.tsx +++ b/packages/app/src/components/SQLEditor/SQLInlineEditor.tsx @@ -242,6 +242,7 @@ export default function SQLInlineEditor({ // Enable line wrapping when multiline is allowed (regardless of focus) ...(allowMultiline ? [EditorView.lineWrapping] : []), + // eslint-disable-next-line react-hooks/refs compartmentRef.current.of( clickhouseSql({ upperCaseKeywords: true, diff --git a/packages/app/src/components/TimePicker/TimePicker.tsx b/packages/app/src/components/TimePicker/TimePicker.tsx index 31bd000f64..d06a0828fd 100644 --- a/packages/app/src/components/TimePicker/TimePicker.tsx +++ b/packages/app/src/components/TimePicker/TimePicker.tsx @@ -135,7 +135,7 @@ const TimePickerComponent = ({ } } // only run when dateRange changes or opened state changes - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps }, [dateRange, opened, mode]); const handleRelativeSearch = React.useCallback( diff --git a/packages/app/src/hooks/useResizable.tsx b/packages/app/src/hooks/useResizable.tsx index bb56bfc0d5..fcc4ac51ce 100644 --- a/packages/app/src/hooks/useResizable.tsx +++ b/packages/app/src/hooks/useResizable.tsx @@ -52,7 +52,7 @@ function useResizable( const endResize = useCallback(() => { document.removeEventListener('mousemove', handleResize); - + // eslint-disable-next-line react-hooks/immutability document.removeEventListener('mouseup', endResize); }, [handleResize]); diff --git a/packages/app/src/hooks/useTableSearch.ts b/packages/app/src/hooks/useTableSearch.ts index 40dbca9c78..c694054f28 100644 --- a/packages/app/src/hooks/useTableSearch.ts +++ b/packages/app/src/hooks/useTableSearch.ts @@ -97,7 +97,7 @@ export function useTableSearch({ shouldScrollToMatchRef.current = true; } // Otherwise keep the current match index as is (loading more data shouldn't change position) - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps }, [debouncedSearchQuery, rows, searchableColumns]); // Handle visibility changes @@ -146,6 +146,7 @@ export function useTableSearch({ shouldScrollToMatchRef.current = false; }, []); + // eslint-disable-next-line react-hooks/refs return { searchQuery: debouncedSearchQuery, inputValue, @@ -154,6 +155,7 @@ export function useTableSearch({ currentMatchIndex, isSearchVisible, setIsSearchVisible, + // eslint-disable-next-line react-hooks/refs shouldScrollToMatch: shouldScrollToMatchRef.current, clearShouldScrollToMatch, handlePreviousMatch, diff --git a/packages/app/src/searchFilters.tsx b/packages/app/src/searchFilters.tsx index e7903b31be..ff7c77d4d3 100644 --- a/packages/app/src/searchFilters.tsx +++ b/packages/app/src/searchFilters.tsx @@ -420,7 +420,7 @@ export const useSearchPageFilterState = ({ setFilters(parsedQuery.filters); } // only react to changes in parsed query - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line @eslint-react/exhaustive-deps }, [parsedQuery.filters]); const updateFilterQuery = React.useCallback( diff --git a/packages/app/src/timeQuery.ts b/packages/app/src/timeQuery.ts index f8f24f3d68..175fa35159 100644 --- a/packages/app/src/timeQuery.ts +++ b/packages/app/src/timeQuery.ts @@ -243,12 +243,13 @@ export function useTimeQuery({ liveTailTimeRange == null && tempLiveTailTimeRange == null && !isInputTimeQueryLive(inputTimeQuery) && + // eslint-disable-next-line react-hooks/refs inputTimeQueryDerivedTimeQueryRef.current != null ) { // Use the input time query, allows users to specify relative time ranges // via url ex. /logs?tq=Last+30+minutes // return inputTimeQueryDerivedTimeQuery as [Date, Date]; - + // eslint-disable-next-line react-hooks/refs return inputTimeQueryDerivedTimeQueryRef.current; } else if ( isReady && @@ -344,6 +345,7 @@ export function useTimeQuery({ ], ); + // eslint-disable-next-line react-hooks/refs return { isReady, // Don't search until we know what we want to do isLive, diff --git a/packages/app/src/useQueryParam.tsx b/packages/app/src/useQueryParam.tsx index 0f4f3ef77b..5684086598 100644 --- a/packages/app/src/useQueryParam.tsx +++ b/packages/app/src/useQueryParam.tsx @@ -28,6 +28,7 @@ export const QueryParamProvider = ({ const setState = useCallback( (state: Record) => { + // eslint-disable-next-line react-hooks/immutability setCache(oldCache => { const newCache = { ...oldCache, diff --git a/packages/app/src/utils.ts b/packages/app/src/utils.ts index 1aa0b57250..e20b5b1d91 100644 --- a/packages/app/src/utils.ts +++ b/packages/app/src/utils.ts @@ -643,7 +643,7 @@ export const usePrevious = (value: T): T | undefined => { useEffect(() => { ref.current = value; }); - + // eslint-disable-next-line react-hooks/refs return ref.current; };