Skip to content

Upgrade ESLint to v10 and adopt @eslint-react#1017

Merged
krusche merged 10 commits into
developfrom
chore/eslint-10-upgrade
May 11, 2026
Merged

Upgrade ESLint to v10 and adopt @eslint-react#1017
krusche merged 10 commits into
developfrom
chore/eslint-10-upgrade

Conversation

@krusche
Copy link
Copy Markdown
Member

@krusche krusche commented May 11, 2026

Summary

  • Migrates the client from ESLint 9.39.4 → 10.3.0 ahead of the ESLint 9 EOL on 2026-08-06.
  • Replaces 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.
  • Audits and strengthens the rule set: removes silenced rules that defeated type safety, adds type-aware bug-catching rules from typescript-eslint, and adds code-quality rules covering common JS/TS footguns.

Toolchain changes

Package Before After Notes
eslint 9.39.4 10.3.0 Node ≥20.19.0; project is on ≥24.7.0 ✅
@eslint/js 9.39.4 10.0.1 Match major
eslint-plugin-react 7.37.5 removed Incompatible with ESLint 10
@eslint-react/eslint-plugin 5.7.5 added React 19-native, peer eslint ^10.3.0
@eslint/compat 2.1.0 removed FlatCompat shim no longer needed
@eslint/eslintrc 3.3.5 removed Same — native flat config used throughout
@typescript-eslint/* 8.59.2 unchanged Already supports ESLint 10

The ESLint ajv@8 workaround 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):

Rule Severity Catches
await-thenable error Awaiting non-Promises (always wrong)
no-floating-promises warn Unhandled async — promote to error after backlog
no-misused-promises warn Async event handlers swallowing errors
no-unnecessary-type-assertion warn Dead as Foo casts
prefer-nullish-coalescing warn ||?? for null/undefined
prefer-optional-chain warn Modern syntax

Added (code quality):
consistent-type-imports (auto-fixed 315 imports to import type for better treeshaking), no-non-null-assertion, no-explicit-any (warn), eqeqeq: ['error', 'smart'], no-throw-literal, no-implicit-coercion (with boolean: false so !!x keeps TS narrowing in && chains), no-console.

Intentionally off:

  • no-undef/no-redeclare — TypeScript already enforces both; no-redeclare rejects legitimate function overloads.
  • strict-boolean-expressions, return-await — too noisy / stylistic.

Latent bugs fixed by the stricter linter (12)

  • requests/handler.ts — removed duplicate else if (status === 404) (unreachable dead branch).
  • DropDownMultiSelect.tsxlet filteredData = data always overwritten → const ternary.
  • ThesisCommentsList.tsx / CalendarCarousel.tsx<> as map root needing a key → <Fragment key={…}>.
  • utils/format.tsgetInterviewStateColor called useMantineColorScheme() from a non-hook function (rules-of-hooks violation). Refactored to accept isDark: boolean; 3 call sites updated.
  • TopicCardGrid.tsx — hook was called conditionally (gridContent ?? useTopicsContext()). Now always calls useContext then chooses.
  • InterviewBookingPage.tsx — hoisted PascalCase function SlotInformation to a real module-scope component.
  • CollapsibleDateCard.tsx, SlotItem.tsx, CollapsibleTopicElement.tsx — removed JSX IIFEs flagged by React Compiler rules.
  • ResearchGroupAdminPage.tsx — moved key before spread props (avoids JSX deopt).
  • AuthenticatedArea.tsx, ResearchGroupSettingPage.tsx==/!====/!==.
  • EmailTemplateEditPage.tsx — removed async/await from two functions that call doRequest with 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 --version reports v10.3.0
  • npm run lint exits 0 errors
  • npx tsc --noEmit clean
  • npm install resolves with no peer-dep warnings
  • Pre-commit hook: stage a .tsx change and verify npx eslint --fix still works
  • npm run dev and click through one route — verify webpack pipeline picks up the new config

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings May 11, 2026 09:47
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Important

Review skipped

Too many files!

This PR contains 199 files, which is 49 over the limit of 150.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02619b97-796f-40e9-bdce-373e3a13e92e

📥 Commits

Reviewing files that changed from the base of the PR and between 45611c2 and 7e9e1d9.

⛔ Files ignored due to path filters (1)
  • client/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (199)
  • client/eslint.config.mjs
  • client/package.json
  • client/patches/@eslint+eslintrc+3.3.5.patch
  • client/patches/eslint+10.3.0.patch
  • client/src/app/layout/AuthenticatedArea/AuthenticatedArea.tsx
  • client/src/app/layout/ContentContainer/ContentContainer.tsx
  • client/src/app/layout/PublicArea/PublicArea.tsx
  • client/src/components/ApplicationData/ApplicationData.tsx
  • client/src/components/ApplicationDeleteButton/ApplicationDeleteButton.tsx
  • client/src/components/ApplicationModal/ApplicationModal.tsx
  • client/src/components/ApplicationRejectButton/ApplicationRejectButton.tsx
  • client/src/components/ApplicationReviewForm/ApplicationReviewForm.tsx
  • client/src/components/ApplicationsFilters/ApplicationsFilters.tsx
  • client/src/components/ApplicationsTable/ApplicationsTable.tsx
  • client/src/components/AuthenticatedFileDownloadButton/AuthenticatedFileDownloadButton.tsx
  • client/src/components/AuthenticatedFilePreview/AuthenticatedFilePreview.tsx
  • client/src/components/AuthenticatedFilePreviewButton/AuthenticatedFilePreviewButton.tsx
  • client/src/components/AvatarUser/AvatarUser.tsx
  • client/src/components/AvatarUserList/AvatarUserList.tsx
  • client/src/components/ConfirmationButton/ConfirmationButton.tsx
  • client/src/components/CustomAvatar/CustomAvatar.tsx
  • client/src/components/DocumentEditor/DocumentEditor.tsx
  • client/src/components/DropDownMultiSelect/DropDownMultiSelect.tsx
  • client/src/components/EnvironmentBanner/EnvironmentBanner.tsx
  • client/src/components/FileElement/FileElement.tsx
  • client/src/components/FilePreview/FilePreview.tsx
  • client/src/components/Footer/Footer.tsx
  • client/src/components/GanttChart/GanttChart.tsx
  • client/src/components/GanttChart/components/GanttChartTicks/GanttChartTicks.tsx
  • client/src/components/GanttChart/components/GanttChartZoomContainer/GanttChartZoomContainer.tsx
  • client/src/components/GanttChart/context.ts
  • client/src/components/InterviewSlotInformation/InterviewSlotInformation.tsx
  • client/src/components/KeycloakUserAutocomplete.tsx/KeycloakUserAutocomplete.tsx
  • client/src/components/LabeledItem/LabeledItem.tsx
  • client/src/components/Logo/Logo.tsx
  • client/src/components/NoContentFoundCard/NoContentFoundCard.tsx
  • client/src/components/PresentationsTable/PresentationsTable.tsx
  • client/src/components/PresentationsTable/components/ReplacePresentationModal/ReplacePresentationModal.tsx
  • client/src/components/PresentationsTable/components/SchedulePresentationModal/SchedulePresentationModal.tsx
  • client/src/components/PublicPresentationsTable/PublicPresentationsTable.tsx
  • client/src/components/ResearchGroupForm/ResearchGroupForm.test.tsx
  • client/src/components/ResearchGroupForm/ResearchGroupForm.tsx
  • client/src/components/ThesesFilters/ThesesFilters.tsx
  • client/src/components/ThesesGanttChart/ThesesGanttChart.tsx
  • client/src/components/ThesesTable/ThesesTable.tsx
  • client/src/components/ThesisCommentsForm/ThesisCommentsForm.tsx
  • client/src/components/ThesisCommentsList/ThesisCommentsList.tsx
  • client/src/components/ThesisCommentsList/components/ThesisCommentElement.tsx
  • client/src/components/ThesisData/ThesisData.tsx
  • client/src/components/ThesisStateBadge/ThesisStateBadge.tsx
  • client/src/components/TopicAccordionItem/TopicAccordionItem.tsx
  • client/src/components/TopicData/TopicData.tsx
  • client/src/components/TopicSearchFilters/TopicSearchFilters.tsx
  • client/src/components/TopicsFilters/TopicsFilters.tsx
  • client/src/components/TopicsTable/TopicsTable.tsx
  • client/src/components/UploadArea/UploadArea.tsx
  • client/src/components/UploadFileButton/UploadFileButton.tsx
  • client/src/components/UserCard/UserCard.tsx
  • client/src/components/UserInformationForm/UserInformationForm.tsx
  • client/src/components/UserInformationForm/components/AvatarInput/AvatarInput.tsx
  • client/src/components/UserInformationRow/UserInformationRow.tsx
  • client/src/components/UserMultiSelect/UserMultiSelect.tsx
  • client/src/config/global.ts
  • client/src/hooks/authentication.ts
  • client/src/hooks/fetcher.ts
  • client/src/hooks/local-storage.ts
  • client/src/hooks/notification.ts
  • client/src/hooks/utility.ts
  • client/src/index.tsx
  • client/src/pages/AboutPage/AboutPage.tsx
  • client/src/pages/AdminPage/AdminPage.tsx
  • client/src/pages/BrowseThesesPage/components/CreateThesisModal/CreateThesisModal.tsx
  • client/src/pages/DashboardPage/DashboardPage.tsx
  • client/src/pages/DashboardPage/components/MyTasksSection/MyTasksSection.tsx
  • client/src/pages/ImprintPage/ImprintPage.tsx
  • client/src/pages/InterviewBookingPage/InterviewBookingPage.tsx
  • client/src/pages/InterviewBookingPage/components/SelectSlotCarousel.tsx
  • client/src/pages/InterviewOverviewPage/InterviewOverviewPage.tsx
  • client/src/pages/InterviewOverviewPage/components/CreateInterviewProcess.tsx
  • client/src/pages/InterviewOverviewPage/components/InterviewProcessCard.tsx
  • client/src/pages/InterviewOverviewPage/components/SelectApplicantsList.tsx
  • client/src/pages/InterviewOverviewPage/components/SelectTopicInterviewProcessItem.tsx
  • client/src/pages/InterviewOverviewPage/components/UpcomingInterviewCard.tsx
  • client/src/pages/InterviewTopicOverviewPage/InterviewTopicOverviewPage.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/AcceptApplicantModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/AddIntervieweesModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/AddSlotsModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/AssignIntervieweeToSlotModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/CalendarCarousel.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/CancelSlotConfirmationModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/CollapsibleDateCard.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/DateHeaderItem.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/IntervieweeCard.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/IntervieweesList.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/InviteConfirmationModal.tsx
  • client/src/pages/InterviewTopicOverviewPage/components/SlotItem.tsx
  • client/src/pages/IntervieweeAssementPage/IntervieweeAssesmentPage.tsx
  • client/src/pages/IntervieweeAssementPage/components/InterviewNoteCard.tsx
  • client/src/pages/IntervieweeAssementPage/components/ScoreCard.tsx
  • client/src/pages/LandingPage/LandingPage.tsx
  • client/src/pages/LandingPage/components/LandingPageHeader/LandingPageHeader.tsx
  • client/src/pages/LandingPage/components/PublishedTheses/PublishedTheses.tsx
  • client/src/pages/LandingPage/components/TopicCardGrid/TopicCard/TopicCard.tsx
  • client/src/pages/LandingPage/components/TopicCardGrid/TopicCardGrid.tsx
  • client/src/pages/LogoutPage/LogoutPage.tsx
  • client/src/pages/ManageTopicsPage/ManageTopicsPage.tsx
  • client/src/pages/ManageTopicsPage/components/CloseTopicButton/CloseTopicButton.tsx
  • client/src/pages/ManageTopicsPage/components/ReplaceTopicModal/ReplaceTopicModal.tsx
  • client/src/pages/PresentationOverviewPage/PresentationOverviewPage.tsx
  • client/src/pages/PresentationOverviewPage/wheelGuard.test.ts
  • client/src/pages/PresentationPage/PresentationPage.tsx
  • client/src/pages/PrivacyPage/PrivacyPage.tsx
  • client/src/pages/ReplaceApplicationPage/ReplaceApplicationPage.tsx
  • client/src/pages/ReplaceApplicationPage/components/MotivationStep/MotivationStep.tsx
  • client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/SelectTopicStep.tsx
  • client/src/pages/ReplaceApplicationPage/components/SelectTopicStep/components/CollapsibleTopicElement.tsx
  • client/src/pages/ResearchGroupAdminPage/ResearchGroupAdminPage.tsx
  • client/src/pages/ResearchGroupAdminPage/components/ResearchGroupCard.tsx
  • client/src/pages/ResearchGroupSettingPage/ResearchGroupSettingPage.tsx
  • client/src/pages/ResearchGroupSettingPage/components/ApplicationEmailContentSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/ApplicationPhaseSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplateCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplateEditPage.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplatePreviewModal.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTemplatesOverview.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/EmailTextEditor.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/Extension.ts
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/VariableComboboxOptions.tsx
  • client/src/pages/ResearchGroupSettingPage/components/EmailTemplateSettings/EmailTextEditor/VariableComponent.tsx
  • client/src/pages/ResearchGroupSettingPage/components/GeneralResearchGroupSettings.tsx
  • client/src/pages/ResearchGroupSettingPage/components/GradingSchemeSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/MemberSettings/DeleteMemberModal.tsx
  • client/src/pages/ResearchGroupSettingPage/components/MemberSettings/ResearchGroupMembers.tsx
  • client/src/pages/ResearchGroupSettingPage/components/PresentationSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/ProposalSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/ResearchGroupSettingsCard.tsx
  • client/src/pages/ResearchGroupSettingPage/components/ScientificWritingGuideSettingsCard.tsx
  • client/src/pages/ReviewApplicationPage/ReviewApplicationPage.tsx
  • client/src/pages/ReviewApplicationPage/components/ApplicationListItem/ApplicationListItem.tsx
  • client/src/pages/ReviewApplicationPage/components/ApplicationReviewBody/ApplicationReviewBody.tsx
  • client/src/pages/ReviewApplicationPage/components/ApplicationsSidebar/ApplicationsSidebar.tsx
  • client/src/pages/ReviewApplicationPage/components/ApplicationsSidebar/keyNavigationFilter.ts
  • client/src/pages/SettingsPage/SettingsPage.tsx
  • client/src/pages/SettingsPage/components/AccountDeletion/AccountDeletion.tsx
  • client/src/pages/SettingsPage/components/DataExport/DataExport.tsx
  • client/src/pages/SettingsPage/components/NotificationSettings/components/NotificationSelect/NotificationSelect.tsx
  • client/src/pages/SettingsPage/components/NotificationSettings/components/NotificationToggleSwitch/NotificationToggleSwitch.tsx
  • client/src/pages/ThesisPage/components/FileHistoryTable/FileHistoryTable.tsx
  • client/src/pages/ThesisPage/components/ThesisAssessmentSection/components/ReplaceAssessmentModal/ReplaceAssessmentModal.tsx
  • client/src/pages/ThesisPage/components/ThesisConfigSection/ThesisConfigSection.tsx
  • client/src/pages/ThesisPage/components/ThesisFeedbackOverview/ThesisFeedbackOverview.tsx
  • client/src/pages/ThesisPage/components/ThesisFeedbackRequestButton/ThesisFeedbackRequestButton.tsx
  • client/src/pages/ThesisPage/components/ThesisFinalGradeSection/ThesisFinalGradeSection.tsx
  • client/src/pages/ThesisPage/components/ThesisFinalGradeSection/components/SubmitFinalGradeModal/SubmitFinalGradeModal.tsx
  • client/src/pages/ThesisPage/components/ThesisInfoSection/ThesisInfoSection.tsx
  • client/src/pages/ThesisPage/components/ThesisInfoSection/components/DownloadAllFilesButton/DownloadAllFilesButton.tsx
  • client/src/pages/ThesisPage/components/ThesisPresentationSection/ThesisPresentationSection.tsx
  • client/src/pages/ThesisPage/components/ThesisPresentationSection/components/PresentationCard.tsx
  • client/src/pages/ThesisPage/components/ThesisProposalSection/ThesisProposalSection.tsx
  • client/src/pages/ThesisPage/components/ThesisStudentInfoSection/ThesisStudentInfoSection.tsx
  • client/src/pages/ThesisPage/components/ThesisVisibilitySelect/ThesisVisibilitySelect.tsx
  • client/src/pages/ThesisPage/components/ThesisWritingSection/ThesisWritingSection.tsx
  • client/src/pages/TopicPage/components/TopicAdittionalInformationCard.tsx
  • client/src/providers/ApplicationsProvider/ApplicationsProvider.tsx
  • client/src/providers/ApplicationsProvider/context.ts
  • client/src/providers/ApplicationsProvider/hooks.ts
  • client/src/providers/AuthenticationContext/AuthenticationProvider.tsx
  • client/src/providers/AuthenticationContext/context.ts
  • client/src/providers/InterviewProcessProvider/InterviewProcessProvider.tsx
  • client/src/providers/InterviewProcessProvider/context.ts
  • client/src/providers/InterviewProcessProvider/hooks.ts
  • client/src/providers/ThesesProvider/ThesesProvider.tsx
  • client/src/providers/ThesesProvider/context.ts
  • client/src/providers/ThesesProvider/hooks.ts
  • client/src/providers/ThesisCommentsProvider/ThesisCommentsProvider.tsx
  • client/src/providers/ThesisCommentsProvider/context.ts
  • client/src/providers/ThesisCommentsProvider/hooks.ts
  • client/src/providers/ThesisProvider/ThesisProvider.tsx
  • client/src/providers/ThesisProvider/context.ts
  • client/src/providers/ThesisProvider/hooks.ts
  • client/src/providers/TopicsProvider/TopicsProvider.tsx
  • client/src/providers/TopicsProvider/context.ts
  • client/src/providers/TopicsProvider/hooks.ts
  • client/src/requests/handler.ts
  • client/src/requests/request.ts
  • client/src/requests/responses/application.ts
  • client/src/requests/responses/emailtemplate.ts
  • client/src/requests/responses/interview.ts
  • client/src/requests/responses/researchGroup.ts
  • client/src/requests/responses/thesis.ts
  • client/src/requests/responses/topic.ts
  • client/src/utils/customDataLink.tsx
  • client/src/utils/file.ts
  • client/src/utils/format.ts
  • client/src/utils/thesis.ts
  • client/src/utils/user.ts
  • client/test/render.tsx
  • client/test/setup.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/eslint-10-upgrade

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-plugin with an updated flat config.
  • Regenerate the AJV compatibility patch for ESLint 10 and remove the now-unneeded @eslint/eslintrc patch.
  • 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.

Comment thread client/src/providers/InterviewProcessProvider/context.ts
Copy link
Copy Markdown
Collaborator

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

krusche and others added 3 commits May 11, 2026 11:58
…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>
Copy link
Copy Markdown
Collaborator

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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>
Copy link
Copy Markdown
Collaborator

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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>
Copy link
Copy Markdown
Collaborator

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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>
@krusche krusche merged commit 2492e0e into develop May 11, 2026
10 of 11 checks passed
@krusche krusche deleted the chore/eslint-10-upgrade branch May 11, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants