chore(deps): update dependency Next.js to v16#3003
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughUpgrades Next.js to 16 and React to 19; converts next.config to typed TypeScript with a turbopack SVG rule; updates tsconfig settings; pins dependencies; migrates toast system to react-hot-toast with a new useToasts hook and Toaster in _app; replaces consumer imports across many components; adds explicit JSX type imports and small typings/UI/CI/prettier tweaks. ChangesReact 19 and Next.js 16 Upgrade
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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 |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/hooks/useClickOutside.ts (1)
22-26:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPre-existing listener leak:
removeEventListeneris missing the{ capture: true }flag.The listener registered at line 22 with
{ capture: true }will never be removed by the cleanup at line 25, becauseremoveEventListenerwithout a matchingcaptureflag targets the bubble phase — a different listener entirely. Since[ref, callback]are dependencies, each re-registration adds a new capture-phase listener that accumulates without being cleaned up.🐛 Proposed fix
- document.body.removeEventListener('click', handleBodyClick); + document.body.removeEventListener('click', handleBodyClick, { capture: true });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useClickOutside.ts` around lines 22 - 26, The cleanup is removing the wrong listener because removeEventListener omits the capture flag; update the cleanup in useClickOutside so it calls document.body.removeEventListener('click', handleBodyClick, { capture: true }) to match the registration (document.body.addEventListener('click', handleBodyClick, { capture: true })), ensuring handleBodyClick registrations are properly removed when dependencies change.package.json (1)
41-41:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift
@headlessui/react@1.7.19is incompatible with React 19 and will cause runtime errors.
@headlessui/reactv1.7.19 accesses React's internalSECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, which was renamed in React 19. This produces a runtime import error:'SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' is not exported from 'react'.The minimum compatible version is
@headlessui/react@2.2.0+(full React 19 support added October 2024). Use the latest stable v2.2.9 or higher. Note that upgrading from v1 → v2 involves breaking API changes and requires a migration pass across all Headless UI usage in the codebase (currently 34+ component files).🔧 Suggested version bump
- "@headlessui/react": "1.7.19", + "@headlessui/react": "^2.2.9",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@package.json` at line 41, package.json currently pins "@headlessui/react" to "1.7.19", which is incompatible with React 19; update the dependency entry for "@headlessui/react" to a React‑19 compatible release (e.g. "2.2.9" or later), run your package manager to update the lockfile (npm/yarn/pnpm install), then perform the required migration across Headless UI usages (search for all imports of "@headlessui/react" and update component APIs per the v2 migration guide across the ~34+ component files), run the test suite and smoke the UI to verify behavior, and commit the updated package.json and lockfile.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@package.json`:
- Line 41: package.json currently pins "@headlessui/react" to "1.7.19", which is
incompatible with React 19; update the dependency entry for "@headlessui/react"
to a React‑19 compatible release (e.g. "2.2.9" or later), run your package
manager to update the lockfile (npm/yarn/pnpm install), then perform the
required migration across Headless UI usages (search for all imports of
"@headlessui/react" and update component APIs per the v2 migration guide across
the ~34+ component files), run the test suite and smoke the UI to verify
behavior, and commit the updated package.json and lockfile.
In `@src/hooks/useClickOutside.ts`:
- Around line 22-26: The cleanup is removing the wrong listener because
removeEventListener omits the capture flag; update the cleanup in
useClickOutside so it calls document.body.removeEventListener('click',
handleBodyClick, { capture: true }) to match the registration
(document.body.addEventListener('click', handleBodyClick, { capture: true })),
ensuring handleBodyClick registrations are properly removed when dependencies
change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c4db1cb9-918c-4a72-9f12-d6c89fba766f
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
next-env.d.tsnext.config.tspackage.jsonserver/tsconfig.jsonsrc/components/Common/Accordion/index.tsxsrc/components/Common/Button/index.tsxsrc/components/Common/Tag/index.tsxsrc/components/Common/Tooltip/index.tsxsrc/components/Layout/MobileMenu/index.tsxsrc/components/Login/index.tsxsrc/components/ManageSlideOver/index.tsxsrc/components/Slider/index.tsxsrc/hooks/useClickOutside.tssrc/hooks/useVerticalScroll.tssrc/pages/_document.tsxtsconfig.json
seerr
|
||||||||||||||||||||||||||||
| Project |
seerr
|
| Branch Review |
chore/upgrade-next
|
| Run status |
|
| Run duration | 02m 17s |
| Commit |
|
| Committer | Gauthier |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
0
|
|
|
0
|
|
|
0
|
|
|
0
|
|
|
32
|
| View all changes introduced in this branch ↗︎ | |
72d97c1 to
af01e2d
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/Settings/SettingsJellyfin.tsx (1)
96-110:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
useToasts()is called twice in the same component — consolidate to a single call.Line 96 stores the full hook return as
toasts, then line 110 destructuresaddToastfrom a seconduseToasts()call. This is a migration artifact:syncLibrariesusestoasts.addToast(...)while the Formik submit handler usesaddToast(...)directly. Both are functionally identical since the hook has no internal state, but maintaining two hook instances is misleading and wasteful.🛠️ Proposed fix
- const toasts = useToasts(); ... - const { addToast } = useToasts(); + const { addToast } = useToasts();Then replace the three
toasts.addToast(...)calls insyncLibrarieswithaddToast(...):- toasts.addToast( + addToast( intl.formatMessage( messages.jellyfinSyncFailedAutomaticGroupedFolders ), ... - toasts.addToast( + addToast( intl.formatMessage(messages.jellyfinSyncFailedNoLibrariesFound), ... - toasts.addToast( + addToast( intl.formatMessage(messages.jellyfinSyncFailedGenericError), ...🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Settings/SettingsJellyfin.tsx` around lines 96 - 110, You have two useToasts() calls; remove the first variable assignment "toasts" and keep the single destructured call that provides "addToast" (the one currently on line 110), then update all uses of toasts.addToast(...) (notably inside the syncLibraries function) to call addToast(...) directly and delete the redundant useToasts() invocation so the component uses one toast hook instance.
♻️ Duplicate comments (1)
src/components/Settings/Notifications/NotificationsNtfy/index.tsx (1)
154-201:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSame 3-arg
addToastcallback concern asNotificationsDiscord.tsx.This file uses the identical pattern — capturing
toastIdvia the third callback argument and then callingremoveToast(toastId). The same risk applies: ifsrc/hooks/useToasts.tsxdoes not invoke the callback with the generated ID, the "Sending ntfy test notification…" toast will never be dismissed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/Settings/Notifications/NotificationsNtfy/index.tsx` around lines 154 - 201, The testSettings function relies on the third callback argument of addToast to capture toastId (same issue as NotificationsDiscord.tsx); change it to not depend on that callback: have addToast return the toast id (or read the id from the API you use) and assign toastId from the return value of addToast when calling it in testSettings, then call removeToast(toastId) using that returned id; reference addToast, removeToast and testSettings so you update the call sites here to ensure the "Sending ntfy test notification…" toast is always dismissible regardless of whether the callback is invoked.
🧹 Nitpick comments (1)
src/hooks/useToasts.tsx (1)
9-44: ⚡ Quick win
addToastandremoveToastshould be wrapped inuseCallbackto provide stable references.Both functions are recreated on every render. Since
toastfromreact-hot-toastis a stable module-level import, these functions have no render-cycle dependencies and can use empty dependency arrays. Without this, any consumer that places them in auseCallbackoruseEffectdep array — such asMovieRequestModal.tsx, which listsaddToastat line 141 — effectively disables memoization because the reference changes every render.♻️ Proposed fix
+import { useCallback } from 'react'; import Toast from '@app/components/Toast'; import { toast } from 'react-hot-toast'; ... export const useToasts = () => { - const addToast = ( + const addToast = useCallback(( message: React.ReactNode, options?: ToastOptions, callback?: (id: string) => void ) => { const id = toast.custom( (t) => ( <Toast appearance={options?.appearance || 'info'} onDismiss={() => toast.dismiss(t.id)} transitionState={t.visible ? 'entered' : 'exiting'} > {message} </Toast> ), { duration: options?.autoDismiss !== false ? 4000 : Infinity, } ); if (callback) { callback(id); } - }; + }, []); - const removeToast = (id: string) => { + const removeToast = useCallback((id: string) => { toast.dismiss(id); - }; + }, []); return { addToast, removeToast }; };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useToasts.tsx` around lines 9 - 44, The addToast and removeToast functions in useToasts are recreated every render; wrap both addToast and removeToast in React.useCallback with empty dependency arrays to provide stable references (keep current behavior: use the existing toast.custom call and options handling inside addToast, and toast.dismiss inside removeToast), and ensure any callback parameter handling (the optional callback in addToast) remains unchanged; update the useToasts export to return these memoized functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/components/Settings/SettingsJellyfin.tsx`:
- Around line 96-110: You have two useToasts() calls; remove the first variable
assignment "toasts" and keep the single destructured call that provides
"addToast" (the one currently on line 110), then update all uses of
toasts.addToast(...) (notably inside the syncLibraries function) to call
addToast(...) directly and delete the redundant useToasts() invocation so the
component uses one toast hook instance.
---
Duplicate comments:
In `@src/components/Settings/Notifications/NotificationsNtfy/index.tsx`:
- Around line 154-201: The testSettings function relies on the third callback
argument of addToast to capture toastId (same issue as
NotificationsDiscord.tsx); change it to not depend on that callback: have
addToast return the toast id (or read the id from the API you use) and assign
toastId from the return value of addToast when calling it in testSettings, then
call removeToast(toastId) using that returned id; reference addToast,
removeToast and testSettings so you update the call sites here to ensure the
"Sending ntfy test notification…" toast is always dismissible regardless of
whether the callback is invoked.
---
Nitpick comments:
In `@src/hooks/useToasts.tsx`:
- Around line 9-44: The addToast and removeToast functions in useToasts are
recreated every render; wrap both addToast and removeToast in React.useCallback
with empty dependency arrays to provide stable references (keep current
behavior: use the existing toast.custom call and options handling inside
addToast, and toast.dismiss inside removeToast), and ensure any callback
parameter handling (the optional callback in addToast) remains unchanged; update
the useToasts export to return these memoized functions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f0549c02-c01a-4345-8d7d-bf7445b43b2f
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (79)
.github/workflows/cypress.yml.prettierignorenext-env.d.tsnext.config.tspackage.jsonserver/tsconfig.jsonsrc/components/Blocklist/index.tsxsrc/components/BlocklistBlock/index.tsxsrc/components/CollectionDetails/index.tsxsrc/components/Common/Accordion/index.tsxsrc/components/Common/Button/index.tsxsrc/components/Common/Tag/index.tsxsrc/components/Common/Tooltip/index.tsxsrc/components/Discover/CreateSlider/index.tsxsrc/components/Discover/DiscoverSliderEdit/index.tsxsrc/components/Discover/index.tsxsrc/components/IssueDetails/index.tsxsrc/components/IssueModal/CreateIssueModal/index.tsxsrc/components/Layout/MobileMenu/index.tsxsrc/components/Layout/Sidebar/index.tsxsrc/components/Login/AddEmailModal.tsxsrc/components/Login/JellyfinLogin.tsxsrc/components/Login/index.tsxsrc/components/ManageSlideOver/index.tsxsrc/components/MovieDetails/index.tsxsrc/components/RequestCard/index.tsxsrc/components/RequestList/RequestItem/index.tsxsrc/components/RequestModal/CollectionRequestModal.tsxsrc/components/RequestModal/MovieRequestModal.tsxsrc/components/RequestModal/TvRequestModal.tsxsrc/components/Settings/CopyButton.tsxsrc/components/Settings/Notifications/NotificationsDiscord.tsxsrc/components/Settings/Notifications/NotificationsEmail.tsxsrc/components/Settings/Notifications/NotificationsGotify/index.tsxsrc/components/Settings/Notifications/NotificationsNtfy/index.tsxsrc/components/Settings/Notifications/NotificationsPushbullet/index.tsxsrc/components/Settings/Notifications/NotificationsPushover/index.tsxsrc/components/Settings/Notifications/NotificationsSlack/index.tsxsrc/components/Settings/Notifications/NotificationsTelegram.tsxsrc/components/Settings/Notifications/NotificationsWebPush/index.tsxsrc/components/Settings/Notifications/NotificationsWebhook/index.tsxsrc/components/Settings/OverrideRule/OverrideRuleModal.tsxsrc/components/Settings/RadarrModal/index.tsxsrc/components/Settings/SettingsJellyfin.tsxsrc/components/Settings/SettingsJobsCache/index.tsxsrc/components/Settings/SettingsLogs/index.tsxsrc/components/Settings/SettingsMain/index.tsxsrc/components/Settings/SettingsMetadata.tsxsrc/components/Settings/SettingsNetwork/index.tsxsrc/components/Settings/SettingsPlex.tsxsrc/components/Settings/SettingsUsers/index.tsxsrc/components/Settings/SonarrModal/index.tsxsrc/components/Setup/JellyfinSetup.tsxsrc/components/Setup/index.tsxsrc/components/Slider/index.tsxsrc/components/TitleCard/index.tsxsrc/components/Toast/index.tsxsrc/components/ToastContainer/index.tsxsrc/components/TvDetails/index.tsxsrc/components/UserList/BulkEditModal.tsxsrc/components/UserList/JellyfinImportModal.tsxsrc/components/UserList/PlexImportModal.tsxsrc/components/UserList/index.tsxsrc/components/UserProfile/UserSettings/UserGeneralSettings/index.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsDiscord.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushbullet.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsPushover.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsTelegram.tsxsrc/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsxsrc/components/UserProfile/UserSettings/UserPasswordChange/index.tsxsrc/components/UserProfile/UserSettings/UserPermissions/index.tsxsrc/hooks/useClickOutside.tssrc/hooks/useDiscover.tssrc/hooks/useToasts.tsxsrc/hooks/useVerticalScroll.tssrc/pages/_app.tsxsrc/pages/_document.tsxtsconfig.json
💤 Files with no reviewable changes (1)
- src/components/ToastContainer/index.tsx
✅ Files skipped from review due to trivial changes (19)
- .prettierignore
- src/components/Login/AddEmailModal.tsx
- src/components/Layout/Sidebar/index.tsx
- src/components/CollectionDetails/index.tsx
- server/tsconfig.json
- src/components/Layout/MobileMenu/index.tsx
- src/components/BlocklistBlock/index.tsx
- src/components/ManageSlideOver/index.tsx
- src/pages/_document.tsx
- src/components/Slider/index.tsx
- src/components/Settings/SettingsLogs/index.tsx
- src/components/Common/Tooltip/index.tsx
- src/hooks/useClickOutside.ts
- src/components/Login/index.tsx
- package.json
- src/components/Common/Accordion/index.tsx
- .github/workflows/cypress.yml
- src/hooks/useVerticalScroll.ts
- src/components/Common/Tag/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- next-env.d.ts
- next.config.ts
- src/components/Common/Button/index.tsx
- tsconfig.json
af01e2d to
af21775
Compare
fallenbagel
left a comment
There was a problem hiding this comment.
CI failing due to formatting
It's expected. Next.js v16 is modifiying next-end.d.ts everytime it's running in dev env. |
|
This pull request has merge conflicts. Please resolve the conflicts so the PR can be successfully reviewed and merged. |
https://github.com/seerr-team/seerr/blob/develop/.prettierrc.js#L36-L41 I think you need something similar like this maybe. |
af21775 to
ed14eae
Compare
ed14eae to
2745445
Compare
Description
Update Next.js to v16. I ran the codemod and everything went fine.
How Has This Been Tested?
N/A
Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit
Chores
New Features
Refactor
Bug Fixes