Skip to content

Update NextJS to 16.1.6#547

Merged
heisbrot merged 5 commits intomainfrom
chore/update-next
Feb 2, 2026
Merged

Update NextJS to 16.1.6#547
heisbrot merged 5 commits intomainfrom
chore/update-next

Conversation

@heisbrot
Copy link
Contributor

@heisbrot heisbrot commented Feb 2, 2026

Summary by CodeRabbit

  • New Features

    • Improved calendar navigation with unified chevrons
    • Expanded color palette and added icon helper libraries for richer UI
  • Bug Fixes

    • Enhanced modal accessibility via hidden dialog titles
    • Reduced token retry attempts for faster failure feedback
    • Moved Groups callout to appear after group settings
    • Adjusted tooltip/scroll-area rendering to stabilize display
  • Chores

    • Upgraded core stack (React 19, Next.js 16) and UI/tooling packages
    • Simplified theming and Tailwind configuration; updated Node runtime

@coderabbitai
Copy link

coderabbitai bot commented Feb 2, 2026

Warning

Rate limit exceeded

@heisbrot has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Upgrades core dependencies (React 18→19, Next 14→16), bumps many UI libs (Radix, Framer Motion, Tabler icons), removes Flowbite/theme, extends Tailwind colors, and refactors several UI components (Tooltip, Calendar, DataTable, Modal, Virtual scroller) plus small tooling and utility tweaks.

Changes

Cohort / File(s) Summary
Dependencies & Build Config
package.json, .github/workflows/build_and_push.yml, tsconfig.json
Bumped Node to 20; upgraded Next/React/React-DOM to Next 16 / React 19 and many libs (Radix, Framer Motion, Tabler icons, cmdk); added classnames and react-icons; changed JSX runtime to react-jsx.
Tailwind & Global CSS
tailwind.config.ts, src/app/globals.css
Removed Flowbite content/plugin references; expanded color palette and added netbird/nb-blue colors; set html { @apply bg-nb-gray; } for global background.
Removed Flowbite Theme
src/utils/theme.ts
Removed exported netbirdTheme (Flowbite theme object) and related imports/usages.
Theme Provider / Layout
src/contexts/GlobalThemeProvider.tsx, src/layouts/AppLayout.tsx
Removed Flowbite wrapper and Flowbite-based body/background classes; reduced nesting in theme provider and layout.
Tooltip & DateTime Input
src/components/Tooltip.tsx, src/components/ui/AbsoluteDateTimeInput.tsx
Tooltip: removed asChild usage from Radix Tooltip.Content (now self-closing); AbsoluteDateTimeInput: forwards ref from getRootProps to wrapper element.
Calendar / DayPicker
src/components/ui/Calendar.tsx
Reworked DayPicker classNames keys and component mapping (replaced IconLeft/IconRight with Chevron); renamed many day/cell keys and adjusted nav button positioning and layout classNames.
Virtual Scroller
src/components/VirtualScrollAreaList.tsx
Replaced MemoizedScrollAreaViewport with ScrollAreaViewport wrapped by a new VirtuosoScroller using forwardRef.
Modal Accessibility
src/components/modal/Modal.tsx
Added VisuallyHidden dialog title via DialogPrimitive.Title; restructured content/close button placement for accessibility.
DataTable Row Expansion
src/components/table/DataTable.tsx
Removed Radix Accordion-based row expansion; implemented state-driven inline expansion rendering with additional table row for expanded content.
Analytics & Utilities
src/contexts/AnalyticsProvider.tsx, src/utils/api.tsx, src/modules/remote-access/rdp/*
Hotjar init changed to object syntax hotjar.initialize({ id, sv }); token-expiry retry attempts reduced from 20→4; tightened types for WebCrypto digest calls.
Settings UI
src/modules/settings/GroupsSettings.tsx
Moved a Callout block to the end of the Groups section (UI reorder, no logic change).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • mlsmaycon

Poem

🐰 Hop, hop — deps leap to a brighter day,

Tailwind spreads color where Flowbite slipped away.
Tooltips and tables, calendars prance,
Scrollers and modals take a fresh chance.
A rabbit winks: "Build fast, then play!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Update NextJS to 16.1.6' accurately reflects the main objective, but the changeset encompasses far more than just a Next.js upgrade—including React 19 migration, major dependency updates (Radix UI, Tabler icons, Framer Motion), removal of Flowbite, Tailwind config restructuring, and numerous component refactors. The title captures only the version bump without conveying the scope of this comprehensive modernization effort.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/update-next

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/api.tsx (1)

82-87: ⚠️ Potential issue | 🟡 Minor

Consider making the polling window configurable or extending it slightly.

The isTokenExpired() function polls for token refresh over 2 seconds (4 attempts × 500ms). While this is a grace period to check if automatic refresh already occurred—not the actual refresh timeout—it could be insufficient if the OIDC library's silent renewal takes longer than 2 seconds. Since the library is configured with refresh_time_before_tokens_expiration_in_second: 30, the refresh should typically complete well within 2 seconds under normal conditions. However, on slow networks or heavy load, making this window configurable (or increasing the default to 3–4 seconds) would reduce the risk of unnecessarily forcing a re-login. If you prefer keeping it fixed, document why 2 seconds is acceptable for your deployment scenarios.

🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 71-73: Update the devDependencies for the TypeScript React typings
so they match React 19: bump `@types/react` and `@types/react-dom` to 19.x (ensure
`@types/react` is ^19.0.0 and `@types/react-dom` is compatible 19.x) to satisfy the
peer dependency required by react 19.2.4; modify the entries for "@types/react"
and "@types/react-dom" in package.json, then reinstall (npm/yarn/pnpm) and run
type checks to confirm there are no remaining type mismatches.

In `@src/app/globals.css`:
- Around line 5-7: The html rule in globals.css is missing a semicolon after the
Tailwind `@apply` directive and the Biome parser needs Tailwind directives
enabled; update the html block (the rule containing the `@apply bg-nb-gray`
directive) to terminate the directive with a semicolon, and enable Tailwind
directive parsing by setting the Biome CSS parser option `tailwindDirectives` to
true in your Biome configuration so the `@apply` is recognized.

In `@src/components/table/DataTable.tsx`:
- Around line 498-527: The accordion logic uses row.original.id which is
optional and can be undefined; update the expansion key to use a stable fallback
(e.g., use row.original.id ?? row.id) wherever you read or mutate accordion
state: replace uses in the isExpanded check
(accordion?.includes(row.original.id)), the data-row-id attribute, and the
setAccordion add/remove logic so you never push or check undefined, and ensure
the same computed key is used when calling renderExpandedRow and when toggling
via setAccordion to keep behavior consistent (refer to row.original.id, row.id,
accordion, setAccordion, renderExpandedRow, and TableRowComponent).

In `@src/contexts/AnalyticsProvider.tsx`:
- Line 59: The hotjar.initialize call is using the object form but the project
uses react-hotjar v6.2.0 which expects positional args; update the call to use
hotjar.initialize(hjid, 6) instead of hotjar.initialize({ id: hjid, sv: 6 }) so
Hotjar actually initializes (refer to the hotjar.initialize call and the hjid
symbol in AnalyticsProvider).
🧹 Nitpick comments (5)
src/modules/remote-access/rdp/rdp-certificate-handler.ts (1)

93-94: Consider updating the parameter type instead of casting.

The cast to Uint8Array<ArrayBuffer> addresses TypeScript 5.7+ stricter typing for TypedArrays with the Web Crypto API. While functionally correct, updating the function signature would be cleaner:

- async calculateFingerprint(certBytes: Uint8Array): Promise<string> {
-   const hashBuffer = await crypto.subtle.digest('SHA-256', certBytes as Uint8Array<ArrayBuffer>);
+ async calculateFingerprint(certBytes: Uint8Array<ArrayBuffer>): Promise<string> {
+   const hashBuffer = await crypto.subtle.digest('SHA-256', certBytes);

This pushes the type constraint to the API boundary, making the requirement explicit for callers.

src/modules/remote-access/rdp/useRDPCertificateHandler.ts (1)

46-49: Same casting pattern — consider updating parameter type for consistency.

This mirrors the change in rdp-certificate-handler.ts. For consistency and cleaner code, consider updating the parameter type:

♻️ Suggested refactor
  const calculateFingerprint = useCallback(
-   async (certBytes: Uint8Array): Promise<string> => {
+   async (certBytes: Uint8Array<ArrayBuffer>): Promise<string> => {
      try {
-       const hashBuffer = await crypto.subtle.digest("SHA-256", certBytes as Uint8Array<ArrayBuffer>);
+       const hashBuffer = await crypto.subtle.digest("SHA-256", certBytes);

The current cast is safe and works correctly. This is just a stylistic preference to make the type requirement explicit at the function boundary rather than casting internally.

src/components/VirtualScrollAreaList.tsx (1)

18-22: Add displayName for better debugging.

The VirtuosoScroller component created with forwardRef is missing a displayName. This helps with React DevTools debugging and follows the pattern used elsewhere in this file (e.g., VirtualScrollListItemWrapper.displayName).

Proposed fix
 const VirtuosoScroller = forwardRef<
   HTMLDivElement,
   React.HTMLAttributes<HTMLDivElement>
 >((props, ref) => <ScrollAreaViewport ref={ref} {...props} />);
+VirtuosoScroller.displayName = "VirtuosoScroller";
src/components/modal/Modal.tsx (1)

78-80: Consider accepting a dynamic title for better accessibility.

The hardcoded "Dialog" title satisfies the ARIA requirement but doesn't provide meaningful context to screen reader users. Consider accepting an optional ariaTitle prop that defaults to "Dialog" but can be customized per modal usage.

Proposed approach

Add an optional prop to ModalContentProps:

type ModalContentProps = {
  showClose?: boolean;
  maxWidthClass?: string;
  ariaTitle?: string; // Add this
};

Then use it in the component:

 <VisuallyHidden asChild>
-  <DialogPrimitive.Title>Dialog</DialogPrimitive.Title>
+  <DialogPrimitive.Title>{ariaTitle ?? "Dialog"}</DialogPrimitive.Title>
 </VisuallyHidden>
src/components/ui/Calendar.tsx (1)

56-61: Forward className and other props to Chevron component

The custom Chevron component ignores className, disabled, and size props passed by DayPicker. Forwarding them ensures the chevron respects DayPicker's styling configuration.

♻️ Proposed refactor
-        Chevron: ({ orientation }) =>
-          orientation === "left" ? (
-            <ChevronLeft className="h-4 w-4" />
-          ) : (
-            <ChevronRight className="h-4 w-4" />
-          ),
+        Chevron: ({ orientation, className, ...props }) =>
+          orientation === "left" ? (
+            <ChevronLeft className={cn("h-4 w-4", className)} {...props} />
+          ) : (
+            <ChevronRight className={cn("h-4 w-4", className)} {...props} />
+          ),

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@package.json`:
- Around line 68-73: Add an "engines" field to package.json declaring the Node
requirement and remove duplicate class utility dependency: update package.json
to include "engines": { "node": ">=20.9.0" } to document the Node ≥20.9.0
constraint, and consolidate class utilities by choosing either "classnames" or
"clsx" (remove the other from dependencies and update any imports/usages in the
codebase to the chosen package).

In `@src/components/table/DataTable.tsx`:
- Around line 516-529: The row click handler in DataTable.tsx (the onClick that
checks expandedRow and calls preventDefault()/stopPropagation() and setAccordion
using rowId) incorrectly blocks interactive elements inside cells; update the
handler to first test the event target (via event.target.closest or equivalent)
for interactive selectors (a, button, input, select, textarea, [role="button"])
and if an interactive element is found, return early so you do not call
preventDefault()/stopPropagation() or toggle via setAccordion; otherwise proceed
with the existing expansion logic.
🧹 Nitpick comments (1)
package.json (1)

52-53: Consolidate class name utilities by migrating classnames usage to the cn helper.

classnames is actively used in Button.tsx, SidebarItem.tsx, Notification.tsx, and Calendar.tsx. Since cn wraps clsx with twMerge and provides the same functionality, you can eliminate the classnames dependency by replacing these usages with cn. This reduces bundle size and standardizes the codebase on a single API.

@heisbrot heisbrot merged commit 750f660 into main Feb 2, 2026
4 checks passed
@heisbrot heisbrot deleted the chore/update-next branch February 2, 2026 14:34
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.

2 participants