Upgrade ESLint to v10 and adopt @eslint-react#1017
Conversation
Migrates from ESLint 9.39 to 10.3 ahead of the v9 EOL (2026-08-06). Since eslint-plugin-react has no ESLint 10 release (peer dep ^9.7; maintainer-confirmed incompatibility, PR #3979 still open), this swaps in @eslint-react/eslint-plugin v5 — a modern, actively-maintained linter built for ESLint 10 with native React 19 support. Toolchain - eslint 9.39.4 -> 10.3.0, @eslint/js 9.39.4 -> 10.0.1 - Replaced eslint-plugin-react@7.37.5 with @eslint-react/eslint-plugin@5.7.5 - Removed @eslint/compat and @eslint/eslintrc (FlatCompat shim no longer needed; @typescript-eslint and @eslint-react both ship native flat-config presets) - Regenerated the ESLint ajv-8 workaround patch for v10.3.0 Rule set audit Removed silencing of @typescript-eslint/no-explicit-any (defeated TS safety). Added the high-value type-aware rules from typescript-eslint: await-thenable (error), no-floating-promises and no-misused-promises (warn pending legacy-backlog cleanup), no-unnecessary-type-assertion, prefer-nullish-coalescing, prefer-optional-chain. Added code-quality rules: consistent-type-imports, no-non-null-assertion, no-explicit-any, eqeqeq (smart), no-throw-literal, no-implicit-coercion (with boolean: false so !!x stays usable for TS narrowing), no-console. Kept no-undef / no-redeclare disabled because TypeScript already enforces both and no-redeclare rejects legitimate function overloads. Bug fixes surfaced by the stricter linter - requests/handler.ts: removed duplicate else-if 404 branch (dead code) - DropDownMultiSelect: const-ified an always-reassigned let - ThesisCommentsList / CalendarCarousel: keyed Fragment for map roots - utils/format.ts: getInterviewStateColor() called a hook from a non-hook fn; refactored to accept isDark and updated 3 call sites - TopicCardGrid: hook was called conditionally (gridContent ?? useTopicsContext()); now always calls useContext - InterviewBookingPage: hoisted SlotInformation to a module-scope component (was a PascalCase function defined inside the parent) - CollapsibleDateCard / SlotItem / CollapsibleTopicElement: removed JSX IIFEs flagged by react compiler rules - ResearchGroupAdminPage: moved key before spread to avoid JSX deopt - AuthenticatedArea / ResearchGroupSettingPage: == -> ===, != -> !== - EmailTemplateEditPage: dropped async/await on two functions that call doRequest with a callback (callback overload returns void) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 199 files, which is 49 over the limit of 150. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (199)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mechanical autofix from the new @typescript-eslint/consistent-type-imports rule; also drops an unnecessary type assertion on ResizeObserverMock that no-unnecessary-type-assertion flagged. tsc --noEmit is clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR upgrades the client linting toolchain to ESLint v10 and migrates React linting from eslint-plugin-react to @eslint-react, then applies the resulting autofixes/refactors across the client codebase to satisfy the stricter rule set and avoid React hooks/key pitfalls.
Changes:
- Upgrade ESLint to
10.3.0, remove legacy compat/eslintrc shims, and adopt@eslint-react/eslint-pluginwith an updated flat config. - Regenerate the AJV compatibility patch for ESLint 10 and remove the now-unneeded
@eslint/eslintrcpatch. - Apply codebase-wide lint-driven edits (type-only imports,
Boolean(...)coercions, React key fixes, hooks-safe refactors, and a few small logic cleanups).
Reviewed changes
Copilot reviewed 174 out of 176 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| client/test/setup.ts | Adjust test polyfills (ResizeObserver assignment). |
| client/test/render.tsx | Type-only imports split for React/testing-library types. |
| client/src/utils/user.ts | Convert response import to type-only. |
| client/src/utils/thesis.ts | Type-only imports + Boolean(...) coercion cleanup. |
| client/src/utils/format.ts | Type-only imports; refactor getInterviewStateColor to accept isDark. |
| client/src/utils/file.ts | Convert config type import to type-only. |
| client/src/utils/customDataLink.tsx | Convert ReactNode import to type-only. |
| client/src/requests/responses/topic.ts | Convert response imports to type-only. |
| client/src/requests/responses/thesis.ts | Convert response imports to type-only; tweak isThesis boolean coercion. |
| client/src/requests/responses/researchGroup.ts | Convert response import to type-only. |
| client/src/requests/responses/interview.ts | Convert response imports to type-only. |
| client/src/requests/responses/emailtemplate.ts | Convert response import to type-only. |
| client/src/requests/responses/application.ts | Convert response imports to type-only. |
| client/src/requests/handler.ts | Type-only import; remove duplicated unreachable 404 branch. |
| client/src/providers/TopicsProvider/TopicsProvider.tsx | Type-only imports split; keep runtime imports minimal. |
| client/src/providers/TopicsProvider/context.ts | Type-only imports split for React + response types. |
| client/src/providers/ThesisProvider/ThesisProvider.tsx | Type-only imports split for React/context/thesis. |
| client/src/providers/ThesisProvider/hooks.ts | Convert thesis response import to type-only. |
| client/src/providers/ThesisProvider/context.ts | Convert thesis response import to type-only. |
| client/src/providers/ThesisCommentsProvider/ThesisCommentsProvider.tsx | Type-only imports split for React/context/pagination/thesis. |
| client/src/providers/ThesisCommentsProvider/context.ts | Type-only imports split for React + response types. |
| client/src/providers/ThesesProvider/ThesesProvider.tsx | Type-only imports split for context + response types. |
| client/src/providers/ThesesProvider/context.ts | Type-only imports split for React + response types. |
| client/src/providers/InterviewProcessProvider/InterviewProcessProvider.tsx | Type-only imports split for context + interview response types. |
| client/src/providers/InterviewProcessProvider/context.ts | Type-only imports split; context typing updates. |
| client/src/providers/AuthenticationContext/context.ts | Convert various imports to type-only. |
| client/src/providers/AuthenticationContext/AuthenticationProvider.tsx | Type-only imports split; Boolean(...) coercions; remove non-null assertion. |
| client/src/providers/ApplicationsProvider/hooks.ts | Convert application response import to type-only. |
| client/src/providers/ApplicationsProvider/context.ts | Type-only imports split for React + response types. |
| client/src/providers/ApplicationsProvider/ApplicationsProvider.tsx | Type-only imports split for React/context/pagination/application. |
| client/src/pages/TopicPage/components/TopicAdittionalInformationCard.tsx | Convert topic response import to type-only. |
| client/src/pages/ThesisPage/components/ThesisWritingSection/ThesisWritingSection.tsx | Type-only thesis import split; Boolean(...) coercion. |
| client/src/pages/ThesisPage/components/ThesisVisibilitySelect/ThesisVisibilitySelect.tsx | Type-only SelectProps import split. |
| client/src/pages/ThesisPage/components/ThesisStudentInfoSection/ThesisStudentInfoSection.tsx | Convert thesis response import to type-only. |
| client/src/pages/ThesisPage/components/ThesisProposalSection/ThesisProposalSection.tsx | Type-only thesis import split. |
| client/src/pages/ThesisPage/components/ThesisPresentationSection/components/PresentationCard.tsx | Convert thesis presentation imports to type-only. |
| client/src/pages/ThesisPage/components/ThesisInfoSection/ThesisInfoSection.tsx | Convert thesis response import to type-only. |
| client/src/pages/ThesisPage/components/ThesisInfoSection/components/DownloadAllFilesButton/DownloadAllFilesButton.tsx | Convert pagination/thesis comment imports to type-only. |
| client/src/pages/ThesisPage/components/ThesisFinalGradeSection/ThesisFinalGradeSection.tsx | Type-only thesis import split. |
| client/src/pages/ThesisPage/components/ThesisFinalGradeSection/components/SubmitFinalGradeModal/SubmitFinalGradeModal.tsx | Convert thesis response import to type-only. |
| client/src/pages/ThesisPage/components/ThesisFeedbackRequestButton/ThesisFeedbackRequestButton.tsx | Convert thesis import to type-only; Boolean(...) coercions. |
| client/src/pages/ThesisPage/components/ThesisFeedbackOverview/ThesisFeedbackOverview.tsx | Convert thesis import to type-only; Boolean(...) coercion. |
| client/src/pages/ThesisPage/components/ThesisConfigSection/ThesisConfigSection.tsx | Convert thesis/pagination/researchGroup imports to type-only. |
| client/src/pages/ThesisPage/components/ThesisAssessmentSection/components/ReplaceAssessmentModal/ReplaceAssessmentModal.tsx | Convert thesis/researchGroupSettings imports to type-only. |
| client/src/pages/ThesisPage/components/FileHistoryTable/FileHistoryTable.tsx | Convert user/config type imports to type-only. |
| client/src/pages/SettingsPage/components/NotificationSettings/components/NotificationToggleSwitch/NotificationToggleSwitch.tsx | Type-only React imports split. |
| client/src/pages/ReviewApplicationPage/ReviewApplicationPage.tsx | Type-only application import split. |
| client/src/pages/ReviewApplicationPage/components/ApplicationsSidebar/ApplicationsSidebar.tsx | Convert application import to type-only. |
| client/src/pages/ReviewApplicationPage/components/ApplicationReviewBody/ApplicationReviewBody.tsx | Convert application import to type-only. |
| client/src/pages/ReviewApplicationPage/components/ApplicationListItem/ApplicationListItem.tsx | Convert application import to type-only. |
| client/src/pages/ResearchGroupSettingPage/ResearchGroupSettingPage.tsx | Convert response imports to type-only; strict inequality fix. |
| client/src/pages/ResearchGroupSettingPage/components/ScientificWritingGuideSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/ResearchGroupSettingsCard.tsx | Convert ReactNode import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/ProposalSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/PresentationSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/MemberSettings/ResearchGroupMembers.tsx | Convert user/researchGroup imports to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/MemberSettings/DeleteMemberModal.tsx | Convert user import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/GradingSchemeSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/GeneralResearchGroupSettings.tsx | Convert researchGroup + form values imports to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/VariableComponent.tsx | Type-only imports split for TipTap + DTOs. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/VariableComboboxOptions.tsx | Convert DTO import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/Extension.ts | Convert DTO import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/EmailTextEditor.tsx | Type-only imports split; remove non-null assertion in spread. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplatesOverview.tsx | Convert response imports to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplatePreviewModal.tsx | Convert response imports to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplateEditPage.tsx | Convert response imports to type-only; remove unnecessary async/await. |
| client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplateCard.tsx | Convert template import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/EmailSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/ApplicationPhaseSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupSettingPage/components/ApplicationEmailContentSettingsCard.tsx | Convert researchGroupSettings import to type-only. |
| client/src/pages/ResearchGroupAdminPage/ResearchGroupAdminPage.tsx | Convert response/form-value imports to type-only; reorder JSX key before spread. |
| client/src/pages/ResearchGroupAdminPage/components/ResearchGroupCard.tsx | Convert researchGroup import to type-only. |
| client/src/pages/ReplaceApplicationPage/ReplaceApplicationPage.tsx | Convert application import to type-only. |
| client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/SelectTopicStep.tsx | Convert topic/researchGroup imports to type-only. |
| client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/components/CollapsibleTopicElement.tsx | Refactor to avoid JSX IIFE; compute deadline outside render block. |
| client/src/pages/ReplaceApplicationPage/components/MotivationStep/MotivationStep.tsx | Convert response imports to type-only; Boolean(...) coercion. |
| client/src/pages/PresentationPage/PresentationPage.tsx | Convert published presentation import to type-only. |
| client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx | Convert response imports to type-only; optional chaining simplification. |
| client/src/pages/ManageTopicsPage/ManageTopicsPage.tsx | Boolean(...) coercion for modal open state. |
| client/src/pages/ManageTopicsPage/components/ReplaceTopicModal/ReplaceTopicModal.tsx | Type-only imports split; Boolean(...) coercions. |
| client/src/pages/ManageTopicsPage/components/CloseTopicButton/CloseTopicButton.tsx | Type-only imports split for topic types. |
| client/src/pages/LandingPage/LandingPage.tsx | Convert researchGroup import to type-only. |
| client/src/pages/LandingPage/components/TopicCardGrid/TopicCardGrid.tsx | Hooks-safe context usage: always call useContext, allow gridContent override. |
| client/src/pages/LandingPage/components/TopicCardGrid/TopicCard/TopicCard.tsx | Type-only imports split for Dispatch/response types. |
| client/src/pages/LandingPage/components/PublishedTheses/PublishedTheses.tsx | Convert response imports to type-only; Boolean(...) coercion. |
| client/src/pages/LandingPage/components/LandingPageHeader/LandingPageHeader.tsx | Convert researchGroup import to type-only. |
| client/src/pages/InterviewTopicOverviewPage/InterviewTopicOverviewPage.tsx | Convert interview process import to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/SlotItem.tsx | Convert slot import to type-only; remove JSX IIFE. |
| client/src/pages/InterviewTopicOverviewPage/components/InviteConfirmationModal.tsx | Convert user import to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/IntervieweesList.tsx | Type-only import split; keep InterviewState runtime. |
| client/src/pages/InterviewTopicOverviewPage/components/IntervieweeCard.tsx | Update color helper call to pass isDark. |
| client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx | Convert slot import to type-only; remove JSX IIFE. |
| client/src/pages/InterviewTopicOverviewPage/components/CancelSlotConfirmationModal.tsx | Convert slot import to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/CalendarCarousel.tsx | Convert slot import to type-only; add keyed Fragment in map. |
| client/src/pages/InterviewTopicOverviewPage/components/AssignIntervieweeToSlotModal.tsx | Convert interview imports to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/AddSlotsModal.tsx | Convert slot import to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/AddIntervieweesModal.tsx | Convert response imports to type-only. |
| client/src/pages/InterviewTopicOverviewPage/components/AcceptApplicantModal.tsx | Convert response imports to type-only. |
| client/src/pages/InterviewOverviewPage/InterviewOverviewPage.tsx | Convert response imports to type-only. |
| client/src/pages/InterviewOverviewPage/components/UpcomingInterviewCard.tsx | Convert response import to type-only. |
| client/src/pages/InterviewOverviewPage/components/SelectTopicInterviewProcessItem.tsx | Convert response import to type-only. |
| client/src/pages/InterviewOverviewPage/components/SelectApplicantsList.tsx | Convert response import to type-only. |
| client/src/pages/InterviewOverviewPage/components/InterviewProcessCard.tsx | Update color helper calls to pass isDark. |
| client/src/pages/InterviewOverviewPage/components/CreateInterviewProcess.tsx | Convert pagination/interview imports to type-only. |
| client/src/pages/IntervieweeAssementPage/IntervieweeAssesmentPage.tsx | Convert interviewee import to type-only. |
| client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx | Promote inner SlotInformation function to module-scope component. |
| client/src/pages/InterviewBookingPage/components/SelectSlotCarousel.tsx | Convert slot import to type-only. |
| client/src/pages/DashboardPage/DashboardPage.tsx | Type-only import split; keep ApplicationState runtime. |
| client/src/pages/DashboardPage/components/MyTasksSection/MyTasksSection.tsx | Convert dashboard type import to type-only. |
| client/src/pages/BrowseThesesPage/components/CreateThesisModal/CreateThesisModal.tsx | Convert response imports to type-only. |
| client/src/pages/AdminPage/AdminPage.tsx | Convert user import to type-only. |
| client/src/hooks/notification.ts | Type-only React imports split. |
| client/src/hooks/local-storage.ts | Type-only React imports split. |
| client/src/hooks/fetcher.ts | Convert response imports to type-only. |
| client/src/config/global.ts | Convert config type imports to type-only. |
| client/src/components/UserMultiSelect/UserMultiSelect.tsx | Convert response imports to type-only. |
| client/src/components/UserInformationRow/UserInformationRow.tsx | Convert user import to type-only. |
| client/src/components/UserInformationForm/UserInformationForm.tsx | Convert payload import to type-only. |
| client/src/components/UserInformationForm/components/AvatarInput/AvatarInput.tsx | Convert user import to type-only; Boolean(...) coercion. |
| client/src/components/UserCard/UserCard.tsx | Convert user import to type-only. |
| client/src/components/UploadFileButton/UploadFileButton.tsx | Type-only imports split for UploadFileType/PropsWithChildren. |
| client/src/components/UploadArea/UploadArea.tsx | Convert UploadFileType import to type-only. |
| client/src/components/TopicsTable/TopicsTable.tsx | Split mantine-datatable type import; convert topic types to type-only. |
| client/src/components/TopicsFilters/TopicsFilters.tsx | Boolean(...) coercion in checkbox checked state. |
| client/src/components/TopicSearchFilters/TopicSearchFilters.tsx | Type-only React imports split; convert response imports to type-only. |
| client/src/components/TopicData/TopicData.tsx | Convert topic import to type-only. |
| client/src/components/TopicAccordionItem/TopicAccordionItem.tsx | Type-only React + topic imports split. |
| client/src/components/ThesisStateBadge/ThesisStateBadge.tsx | Convert ThesisState import to type-only. |
| client/src/components/ThesisData/ThesisData.tsx | Split thesis type imports; keep isThesis runtime import. |
| client/src/components/ThesisCommentsList/ThesisCommentsList.tsx | Add keyed Fragment wrapper for mapped children. |
| client/src/components/ThesisCommentsList/components/ThesisCommentElement.tsx | Convert thesis comment import to type-only. |
| client/src/components/ThesisCommentsForm/ThesisCommentsForm.tsx | Boolean(...) coercion for disabled flag. |
| client/src/components/ThesesTable/ThesesTable.tsx | Split mantine-datatable type import; convert types to type-only. |
| client/src/components/ThesesGanttChart/ThesesGanttChart.tsx | Convert context type import to type-only; Boolean(...) coercions. |
| client/src/components/ThesesFilters/ThesesFilters.tsx | Remove unnecessary cast on MultiSelect values. |
| client/src/components/ResearchGroupForm/ResearchGroupForm.tsx | Convert imports to type-only; Boolean(...) for editing detection. |
| client/src/components/ResearchGroupForm/ResearchGroupForm.test.tsx | Convert import to type-only; remove unnecessary DOM element casts. |
| client/src/components/PublicPresentationsTable/PublicPresentationsTable.tsx | Convert response imports to type-only. |
| client/src/components/PresentationsTable/PresentationsTable.tsx | Split mantine-datatable type import; split runtime vs type thesis exports; Boolean(...) coercion. |
| client/src/components/PresentationsTable/components/SchedulePresentationModal/SchedulePresentationModal.tsx | Convert thesis presentation imports to type-only; Boolean(...) coercion. |
| client/src/components/PresentationsTable/components/ReplacePresentationModal/ReplacePresentationModal.tsx | Convert thesis presentation imports to type-only. |
| client/src/components/NoContentFoundCard/NoContentFoundCard.tsx | Convert ReactNode import to type-only. |
| client/src/components/LabeledItem/LabeledItem.tsx | Type-only ReactNode import split. |
| client/src/components/KeycloakUserAutocomplete.tsx/KeycloakUserAutocomplete.tsx | Convert response imports to type-only. |
| client/src/components/InterviewSlotInformation/InterviewSlotInformation.tsx | Convert slot import to type-only. |
| client/src/components/GanttChart/GanttChart.tsx | Type-only imports split for ArrayElement/ReactNode/CSSProperties/context types. |
| client/src/components/GanttChart/context.ts | Type-only imports split for React types. |
| client/src/components/GanttChart/components/GanttChartZoomContainer/GanttChartZoomContainer.tsx | Type-only imports split for React event types + DateRange. |
| client/src/components/Footer/Footer.tsx | Split MantineSize to type-only import. |
| client/src/components/FilePreview/FilePreview.tsx | Convert UploadFileType import to type-only. |
| client/src/components/FileElement/FileElement.tsx | Split Mantine type imports from runtime imports. |
| client/src/components/EnvironmentBanner/EnvironmentBanner.tsx | Split MantineColor/Environment to type-only; Boolean(...) coercion. |
| client/src/components/DropDownMultiSelect/DropDownMultiSelect.tsx | Simplify filtering logic; avoid mutable let reassignment. |
| client/src/components/DocumentEditor/DocumentEditor.tsx | Type-only React imports split for ChangeEvent/ComponentProps. |
| client/src/components/CustomAvatar/CustomAvatar.tsx | Split MantineSize + user types into type-only imports. |
| client/src/components/ConfirmationButton/ConfirmationButton.tsx | Type-only ReactNode import split. |
| client/src/components/AvatarUserList/AvatarUserList.tsx | Split MantineSize + user type into type-only imports. |
| client/src/components/AvatarUser/AvatarUser.tsx | Split MantineSize + user type into type-only imports. |
| client/src/components/AuthenticatedFilePreviewButton/AuthenticatedFilePreviewButton.tsx | Type-only PropsWithChildren + UploadFileType imports. |
| client/src/components/AuthenticatedFilePreview/AuthenticatedFilePreview.tsx | Type-only ReactNode + UploadFileType imports. |
| client/src/components/AuthenticatedFileDownloadButton/AuthenticatedFileDownloadButton.tsx | Type-only PropsWithChildren import split. |
| client/src/components/ApplicationsTable/ApplicationsTable.tsx | Split mantine-datatable type import; convert application/sort imports to type-only. |
| client/src/components/ApplicationsFilters/ApplicationsFilters.tsx | Remove unnecessary cast on MultiSelect values. |
| client/src/components/ApplicationReviewForm/ApplicationReviewForm.tsx | Type-only application/interview imports split. |
| client/src/components/ApplicationRejectButton/ApplicationRejectButton.tsx | Type-only application import split. |
| client/src/components/ApplicationModal/ApplicationModal.tsx | Boolean(...) coercion for opened prop; type-only import split. |
| client/src/components/ApplicationDeleteButton/ApplicationDeleteButton.tsx | Type-only application import split. |
| client/src/components/ApplicationData/ApplicationData.tsx | Type-only imports split for application + ReactNode. |
| client/src/app/layout/PublicArea/PublicArea.tsx | Type-only PropsWithChildren/MantineSize import split. |
| client/src/app/layout/ContentContainer/ContentContainer.tsx | Type-only PropsWithChildren/MantineSize import split. |
| client/src/app/layout/AuthenticatedArea/AuthenticatedArea.tsx | Type-only imports split; strict equality fix; Boolean(...) coercion. |
| client/patches/eslint+10.3.0.patch | New ESLint 10 AJV workaround patch. |
| client/patches/@eslint+eslintrc+3.3.5.patch | Remove obsolete @eslint/eslintrc patch. |
| client/package.json | Upgrade ESLint/@eslint-js; add @eslint-react; remove legacy react plugin/compat deps. |
| client/eslint.config.mjs | Replace FlatCompat-based config with native flat config + @eslint-react + expanded TS ruleset. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Claudia-Anthropica
left a comment
There was a problem hiding this comment.
@krusche Solid migration — the rule-set rationale is clear, and the real wins here are the latent bugs the stricter linter surfaced: the rules-of-hooks fix in format.ts, the conditional-hook fix in TopicCardGrid, the SlotInformation hoist, and the duplicate 404 branch in handler.ts. Verified locally: 0 errors, tests pass, tsc clean.
…cing) Mechanical conversion driven by the new @typescript-eslint/prefer-nullish-coalescing rule. ?? short-circuits only on null/undefined, so for typed-nullable values the change is semantically equivalent to ||. Cases where a falsy primitive value (0, '', false) is legitimately treated as "fall through" keep || with an inline disable comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces useContext(X) with use(X) and <X.Provider> with <X>, the React 19 equivalents recommended by @eslint-react/no-use-context and no-context-provider. Behavior is identical; the new APIs are preferred because use() is also legal in conditionals/loops and the direct Context syntax is one less indirection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three @eslint-react rules were producing 100+ warnings without flagging actual defects in this codebase: - set-state-in-effect (95 warnings): rule discourages calling setState inside useEffect, but the project legitimately does this for async data fetches and event-subscription teardown. The React docs explicitly carve out fetches and subscriptions as valid useEffect+setState cases. - purity (10 warnings): React Compiler hint flagging `new Date()` and `localStorage.getItem()` reads during render. The project doesn't use React Compiler; these reads are intentional and safe. - naming-convention-ref-name (4 warnings): purely stylistic preference that all refs end in `Ref`. Each disable has an inline comment explaining the rationale. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claudia-Anthropica
left a comment
There was a problem hiding this comment.
@krusche The follow-up commits look good: the || → ?? autofix correctly carves out the false short-circuit cases with inline disables, the use() / direct <Context> migration is clean, and the three rule disables (set-state-in-effect, purity, naming-convention-ref-name) all have defensible rationale inline. Lint is 0 errors / 213 warnings, types are clean — happy to approve.
Resolves a subset of @typescript-eslint/no-floating-promises and no-misused-promises warnings. Adds `void` to intentionally ignored Promises and wraps async handlers in `() => void asyncFn()` so JSX attributes typed `() => void` accept them. UploadFileButton's IIFE introduced by the autofix was extracted to a named handler to satisfy @eslint-react/unsupported-syntax (no IIFEs in JSX). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claudia-Anthropica
left a comment
There was a problem hiding this comment.
@krusche Partial follow-up looks good — the void wraps for fire-and-forget async handlers are the right call for no-misused-promises, the documented exhaustive-deps disables explain the intent at each site, and the GanttChartTicks fix to capture ticksRef.current before the cleanup closure (plus replaceChildren() instead of innerHTML = '') is a nice cleanup along the way. Approving.
Removes the `async` keyword from functions that wrap callback-style `doRequest(url, opts, cb)` calls without using await — the keyword only existed to make these return Promise<void>, which is what the lint rules flag. Where async is still required, callers fire-and- forget the Promise with `void` and async event handlers use named handler functions (no IIFEs in JSX, which would trip @eslint-react/unsupported-syntax). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claudia-Anthropica
left a comment
There was a problem hiding this comment.
@krusche The final wrap-up commit looks clean — dropping async from non-awaiting doRequest-callback wrappers and wrapping async event handlers in () => void fn() is exactly the right call. Spot-checked the renamed-to-sync functions (fetchMyBooking, bookSlot, inviteInterviewees, the ResearchGroupMembers handlers, etc.) — none of their call sites await or .then the return, so the behavior is unchanged. Nice job closing out the floating/misused-promise backlog.
Adds missing dependencies to React hook dep arrays where doing so was safe (primitive values, state setters, stable callbacks). Cases where adding the dep would trigger an infinite render loop or where the omission is genuinely intentional (mount-only init, debounced reload, etc.) keep their behavior and carry a single-line eslint-disable comment that names the specific reason. Complex expressions inside dep arrays were extracted to named consts above the hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replaces `any` with proper types or `unknown` where the type can be tightened, last-resort per-line disable with a specific reason when refactoring would balloon scope. - Removes leftover console.log calls and rewrites a couple as console.warn where the message is genuinely useful. - Replaces array-index keys with stable id fields where the list has them; per-line disable on fixed-length skeleton placeholders. - Adds DOMPurify sanitization to Imprint and Privacy pages (defense in depth against future cache poisoning) and disables the rule on the two email-template paths where DOMPurify is already in place. - Wraps Imprint/Privacy fetches in an AbortController. - Migrates one forwardRef to the React 19 ref-prop pattern. - Eliminates remaining non-null assertions, prefer-optional-chain, no-implicit-coercion, and max-len cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two small polish items from the regression-risk review: - ImprintPage / PrivacyPage: the prior .catch silently swallowed every rejection. Now we ignore AbortError (intentional unmount cleanup) and log other failures via console.warn so dev/operators still see real network or sanitization problems. - ReplacePresentationModal: when picking the newly-created presentation from the response, the previous logic fell back to comparing p.scheduledAt === null when the form's date was missing — which would spuriously match an unrelated record with a null scheduledAt. The form already validates date as required so this was practically unreachable, but the new code guards explicitly: no match when no date was submitted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
eslint-plugin-react@7.37.5(no ESLint 10 release — maintainer-confirmed incompatibility, upstream fix PR #3979 still open) with@eslint-react/eslint-plugin@5.7.5— a modern, actively-maintained linter built for ESLint 10 with native React 19 support.typescript-eslint, and adds code-quality rules covering common JS/TS footguns.Toolchain changes
eslint@eslint/jseslint-plugin-react@eslint-react/eslint-plugineslint ^10.3.0@eslint/compat@eslint/eslintrc@typescript-eslint/*The ESLint
ajv@8workaround patch was regenerated for 10.3.0; the eslintrc patch was deleted with its package.Rule set audit
Removed silencing of
@typescript-eslint/no-explicit-any— disabling it defeated the whole point of using TypeScript.Added (type-aware — requires
parserOptions.project):await-thenableerrorno-floating-promiseswarnerrorafter backlogno-misused-promiseswarnno-unnecessary-type-assertionwarnas Foocastsprefer-nullish-coalescingwarn||→??for null/undefinedprefer-optional-chainwarnAdded (code quality):
consistent-type-imports(auto-fixed 315 imports toimport typefor better treeshaking),no-non-null-assertion,no-explicit-any(warn),eqeqeq: ['error', 'smart'],no-throw-literal,no-implicit-coercion(withboolean: falseso!!xkeeps TS narrowing in&&chains),no-console.Intentionally off:
no-undef/no-redeclare— TypeScript already enforces both;no-redeclarerejects legitimate function overloads.strict-boolean-expressions,return-await— too noisy / stylistic.Latent bugs fixed by the stricter linter (12)
requests/handler.ts— removed duplicateelse if (status === 404)(unreachable dead branch).DropDownMultiSelect.tsx—let filteredData = dataalways overwritten →constternary.ThesisCommentsList.tsx/CalendarCarousel.tsx—<>as map root needing a key →<Fragment key={…}>.utils/format.ts—getInterviewStateColorcalleduseMantineColorScheme()from a non-hook function (rules-of-hooks violation). Refactored to acceptisDark: boolean; 3 call sites updated.TopicCardGrid.tsx— hook was called conditionally (gridContent ?? useTopicsContext()). Now always callsuseContextthen chooses.InterviewBookingPage.tsx— hoisted PascalCase functionSlotInformationto a real module-scope component.CollapsibleDateCard.tsx,SlotItem.tsx,CollapsibleTopicElement.tsx— removed JSX IIFEs flagged by React Compiler rules.ResearchGroupAdminPage.tsx— movedkeybefore spread props (avoids JSX deopt).AuthenticatedArea.tsx,ResearchGroupSettingPage.tsx—==/!=→===/!==.EmailTemplateEditPage.tsx— removedasync/awaitfrom two functions that calldoRequestwith a callback (the callback overload returns() => void, not a Promise).Remaining warnings
418 warnings remain (
0 errors) — visible nudges that won't block commits. Top categories:prefer-nullish-coalescing(~120),set-state-in-effect(~95),exhaustive-deps(~81),no-floating-promises(~53),no-misused-promises(~33). These form a prioritised cleanup backlog and will be addressed in follow-up commits.Test plan
npx eslint --versionreportsv10.3.0npm run lintexits0 errorsnpx tsc --noEmitcleannpm installresolves with no peer-dep warnings.tsxchange and verifynpx eslint --fixstill worksnpm run devand click through one route — verify webpack pipeline picks up the new config🤖 Generated with Claude Code