Skip to content

Conversation

@kasya
Copy link
Collaborator

@kasya kasya commented Aug 29, 2025

Resolves #2074

@kasya kasya requested a review from arkid15r as a code owner August 29, 2025 01:47
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

Summary by CodeRabbit

  • New Features

    • API Keys table now shows Expires and includes a Revoke action.
    • Mobile header drawer adds “Star on GitHub” and “Sponsor Us” actions.
  • Bug Fixes

    • Improved text truncation in item lists to prevent overflow.
    • Corrected dark-mode hover styling on social icons and active navbar states.
  • Style

    • Broad UI polish: consistent gap-based spacing, refined borders (border-1), lighter shadows, improved focus styles, and updated form/search inputs.
  • Chores

    • Upgraded Tailwind to v4 and updated PostCSS setup; removed autoprefixer.
    • Dependency updates and Docker config adjustments for new Tailwind setup.

Walkthrough

TailwindCSS is upgraded to v4.1 with corresponding config/build migrations and widespread class updates (gap, border-1, outline-hidden, gradient renames). PostCSS and Tailwind config switch to v4 patterns/ESM. Numerous components and tests adjust classnames. Additional functional edits include new API Keys table columns/actions and Header mobile menu restructuring.

Changes

Cohort / File(s) Summary
Tailwind v4 upgrade: config and build
frontend/package.json, frontend/postcss.config.js, frontend/tailwind.config.mjs, frontend/src/app/globals.css, frontend/docker/Dockerfile, frontend/docker/Dockerfile.e2e.test
Upgrade Tailwind to v4.1; migrate PostCSS plugin to @tailwindcss/postcss; switch Tailwind config to ESM and adjust content/plugins; overhaul globals.css to v4 layering; Dockerfiles copy new Tailwind config files.
Classname migration: components (presentational)
frontend/src/components/* (ActionButton.tsx, Card.tsx, CardDetailsPage.tsx, Footer.tsx, GeneralCompliantComponent.tsx, Header.tsx, InfoBlock.tsx, ItemCardList.tsx, LoadingSpinner.tsx, LogoCarousel.tsx, MetricsCard.tsx, MetricsScoreCircle.tsx, Modal.tsx, ModeToggle.tsx, ModuleCard.tsx, ModuleForm.tsx, MultiSearch.tsx, NavButton.tsx, NavDropDown.tsx, Pagination.tsx, ProgramForm.tsx, ProjectsDashboardNavBar.tsx, RecentReleases.tsx, RepositoriesCard.tsx, ScrollToTop.tsx, Search.tsx, SearchPageLayout.tsx, SingleModuleCard.tsx, SnapshotCard.tsx, SortBy.tsx, ToggleableList.tsx, TopContributorsList.tsx, TruncatedText.tsx, UserCard.tsx, UserMenu.tsx, skeletons/*)
Replace v3 utilities with v4 equivalents and reorders (space-x/y → gap, border → border-1, gradient name tweaks, shrink-0, min-w-10, outline-none → outline-hidden, shadow-sm → shadow-xs). No logic changes except noted separately.
Pages: class updates
frontend/src/app/about/page.tsx, frontend/src/app/page.tsx, frontend/src/app/projects/dashboard/metrics/page.tsx, frontend/src/app/snapshots/[id]/page.tsx, frontend/src/app/snapshots/page.tsx, frontend/src/app/global-error.tsx
Adjust Tailwind classes for spacing, borders, and shadows to align with v4 (space-y → gap, border-1, shadow-xs). No behavioral changes.
Functional UI adjustments
frontend/src/app/settings/api-keys/page.tsx, frontend/src/components/Header.tsx, frontend/src/components/ItemCardList.tsx
API Keys: add “Expires” column and “Actions” (revoke) button; update table borders. Header: restructure mobile submenu rendering and bottom actions layout. ItemCardList: add min-w-0 to enable truncation in flex.
Tests updated for class expectations
frontend/__tests__/unit/components/* (Footer.test.tsx, LoginPageContent.test.tsx, MultiSearch.test.tsx, NavButton.test.tsx, Search.test.tsx, UserMenu.test.tsx)
Update assertions to new classnames (border-1, gap, focus-visible:outline-hidden, etc.).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Assessment against linked issues

Objective Addressed Explanation
Upgrade TailwindCSS to v4.1 (#2074)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Add “Expires” column and “Actions” (revoke) button to API Keys table (frontend/src/app/settings/api-keys/page.tsx) Introduces new table columns and revoke interaction not required for Tailwind upgrade.
Restructure mobile submenu rendering and add bottom actions in Header mobile drawer (frontend/src/components/Header.tsx) Alters menu structure/content beyond Tailwind class migration.
Enable truncation via added min-w-0 on title container (frontend/src/components/ItemCardList.tsx) Functional layout behavior change unrelated to Tailwind version upgrade.

Possibly related PRs

Suggested reviewers

  • arkid15r
  • aramattamara

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch upgrade-tailwindcss

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 17

Caution

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

⚠️ Outside diff range comments (3)
frontend/src/components/ToggleableList.tsx (1)

32-36: Spacing regression: gap-2 is applied to a container with a single child; label is outside.

This defeats the purpose of replacing space-x-2 and also doubles spacing via mr-2. Consolidate into a single flex row and drop the margin.

-        <div className="flex items-center">
-          <div className="flex flex-row items-center gap-2">
-            {icon && <FontAwesomeIcon icon={icon} className="mr-2 h-5 w-5" />}
-          </div>
-          <span>{label}</span>
-        </div>
+        <div className="flex items-center gap-2">
+          {icon && <FontAwesomeIcon icon={icon} className="h-5 w-5" />}
+          <span>{label}</span>
+        </div>
frontend/src/components/ProjectsDashboardNavBar.tsx (1)

31-36: Replace invalid Tailwind utility text-align-left with text-left.

- 'data-[active=true]:text-align-left',
+ 'data-[active=true]:text-left',
frontend/src/components/ScrollToTop.tsx (1)

34-41: Replace invalid variant order and address non-standard duration

  • In frontend/src/components/ScrollToTop.tsx (line 38), change
    - hover:dark:bg-owasp-blue/50
    + dark:hover:bg-owasp-blue/50
  • Remove or replace duration-400 with a default Tailwind duration (e.g., duration-300) or add a duration-400 entry under theme.extend.transitionDuration in tailwind.config.js (no custom duration-400 found in config).
🧹 Nitpick comments (15)
frontend/src/components/GeneralCompliantComponent.tsx (1)

21-21: Remove redundant filter utility.

drop-shadow-* applies the necessary filter; the standalone filter class is unnecessary post-v3 and can be dropped.

-            'h-14 w-14 drop-shadow-md filter transition-all group-hover:drop-shadow-lg',
+            'h-14 w-14 drop-shadow-md transition-all group-hover:drop-shadow-lg',
frontend/src/components/CardDetailsPage.tsx (1)

90-96: Add focus-visible styles for accessibility (align with PR-wide pattern).

-                  className="flex items-center justify-center gap-2 rounded-md border border-[#0D6EFD] bg-transparent px-2 py-2 text-nowrap text-[#0D6EFD] transition-all hover:bg-[#0D6EFD] hover:text-white dark:border-sky-600 dark:text-sky-600 dark:hover:bg-sky-100"
+                  className="flex items-center justify-center gap-2 rounded-md border border-[#0D6EFD] bg-transparent px-2 py-2 text-nowrap text-[#0D6EFD] transition-all hover:bg-[#0D6EFD] hover:text-white focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-[#0D6EFD] focus-visible:ring-offset-2 dark:border-sky-600 dark:text-sky-600 dark:hover:bg-sky-100 dark:focus-visible:ring-sky-400"
frontend/src/components/TruncatedText.tsx (1)

40-40: Nit: drop redundant utilities; truncate already covers them.

In v4, truncate sets overflow-hidden, text-ellipsis, and whitespace-nowrap. You can simplify.

-      className={`block truncate overflow-hidden text-ellipsis whitespace-nowrap ${className}`}
+      className={`block truncate ${className}`}

Reference: Tailwind v4 text-overflow docs. (tailwindcss.com)

frontend/src/components/Search.tsx (2)

81-81: Using focus:outline-hidden is correct for Tailwind v4.

In v4, outline-hidden replaces the v3 behavior formerly provided by outline-none. Keep it, or optionally scope to keyboard users with focus-visible:outline-hidden.

Reference: Tailwind v4 docs and notes on outline-hidden. (tailwindcss.com, github.com)

Optional diff:

-              className="h-12 w-full rounded-lg border border-gray-300 pr-10 pl-10 text-lg text-black focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:focus:border-blue-300 dark:focus:ring-blue-300"
+              className="h-12 w-full rounded-lg border border-gray-300 pr-10 pl-10 text-lg text-black focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus-visible:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:focus:border-blue-300 dark:focus:ring-blue-300"

85-85: Align clear button focus style with input (optional).

Match the input’s keyboard-only outline suppression for consistency.

-                className="absolute top-1/2 right-2 -translate-y-1/2 rounded-full p-1 hover:bg-gray-100 focus:ring-2 focus:ring-gray-300 focus:outline-hidden"
+                className="absolute top-1/2 right-2 -translate-y-1/2 rounded-full p-1 hover:bg-gray-100 focus:ring-2 focus:ring-gray-300 focus-visible:outline-hidden"
frontend/src/components/LoginPageContent.tsx (1)

65-65: Add explicit type to GitHub sign-in button
Include type="button" on the GitHub sign-in <button> to prevent unintended form submissions if this component is ever nested inside a <form>.

LoginPageContent.tsx, around line 65:

-        <button
+        <button type="button"
           onClick={() => signIn('github', { callbackUrl: '/' })}
           className="flex w-full items-center justify-center gap-2 rounded-lg bg-black px-4 py-2 font-medium text-white transition-colors hover:bg-gray-900/90"
frontend/__tests__/unit/components/MultiSearch.test.tsx (1)

332-339: Fix misleading test title (“blur-sm”).

The test doesn’t assert blur or a blur-sm utility; it only checks focus. Rename for clarity.

-    it('handles input focus and blur-sm correctly', async () => {
+    it('handles input focus correctly', async () => {
frontend/src/components/UserMenu.tsx (1)

68-75: Use focus:outline-hidden and add an accessible label.

Style change is good. Consider adding an aria-label to improve SR discoverability of the avatar button.

-      <button
+      <button
         onClick={() => setIsOpen((prev) => !prev)}
         aria-expanded={isOpen}
         aria-haspopup="true"
         aria-controls={dropdownId}
         className="w-auto focus:outline-hidden"
         disabled={isLoggingOut}
+        aria-label="User menu"
       >
frontend/src/app/page.tsx (1)

258-260: Remove redundant text-wrap with truncate.

truncate enforces nowrap; text-wrap/md:text-nowrap here are no-ops. Simplify.

-<h3 className="mb-2 truncate text-lg font-semibold text-wrap md:text-nowrap">
+<h3 className="mb-2 truncate text-lg font-semibold">
frontend/src/components/skeletons/Card.tsx (1)

33-38: Un-sized trailing Skeleton placeholder.

The extra has no dimensions; it may render oddly or affect layout. Either size it or remove it.

-              <Skeleton />
+              {/* Optional trailing placeholder for overflow */}
+              {/* <Skeleton className="h-8 w-16" /> */}
frontend/src/components/ModuleForm.tsx (1)

357-358: Make project selector width responsive.

w-96 can overflow on small screens. Prefer w-full on mobile.

- 'w-96 rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200'
+ 'w-full sm:w-96 rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200'
frontend/src/app/globals.css (2)

120-137: Move element resets to base layer

Universal resets (*, h1, a) belong in @layer base to ensure correct precedence relative to utilities.

-@layer utilities {
+@layer base {
   * { margin:0; padding:0; box-sizing:border-box; }
   h1 { font-size: clamp(1.5rem, 5vw, 2rem); }
   a { color:#1d7bd7; }
   .navlink { color: inherit; }
-}
+}

330-345: Hover-only dropdown hurts a11y

Hover doesn’t support keyboard or touch reliably. Prefer focus-within, aria-expanded, or a disclosure component and target [data-state=open]/[aria-expanded="true"].

-.dropdown:hover .dropdown-menu { @apply visible opacity-100; }
+.dropdown:focus-within .dropdown-menu,
+.dropdown [aria-expanded="true"] + .dropdown-menu { @apply visible opacity-100; }
frontend/src/app/settings/api-keys/page.tsx (1)

330-378: Replace legacy Tailwind small-scale utilities

  • frontend/src/components/Card.tsx (line 47): change shadow-smshadow-xs
  • frontend/src/app/settings/api-keys/page.tsx (line 207): change rounded-smrounded-xs

Audit any other instances of shadow-sm, rounded-sm, or blur-sm and update to the v4 equivalents for consistent styling.

frontend/src/components/skeletons/ApiKeySkelton.tsx (1)

9-10: Minor: purely cosmetic class reordering

Only ordering changed; no behavioral impact.

Consider a formatter (e.g., prettier-plugin-tailwindcss) to enforce consistent class order automatically.

Also applies to: 16-21, 26-38, 56-72

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2f2e260 and e40542b.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (54)
  • frontend/__tests__/unit/components/LoginPageContent.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/MultiSearch.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/NavButton.test.tsx (2 hunks)
  • frontend/__tests__/unit/components/Search.test.tsx (2 hunks)
  • frontend/__tests__/unit/components/UserMenu.test.tsx (1 hunks)
  • frontend/package.json (1 hunks)
  • frontend/postcss.config.js (1 hunks)
  • frontend/src/app/about/page.tsx (2 hunks)
  • frontend/src/app/global-error.tsx (1 hunks)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/src/app/page.tsx (4 hunks)
  • frontend/src/app/projects/dashboard/metrics/page.tsx (1 hunks)
  • frontend/src/app/settings/api-keys/page.tsx (4 hunks)
  • frontend/src/app/snapshots/[id]/page.tsx (2 hunks)
  • frontend/src/app/snapshots/page.tsx (1 hunks)
  • frontend/src/components/Card.tsx (5 hunks)
  • frontend/src/components/CardDetailsPage.tsx (1 hunks)
  • frontend/src/components/Footer.tsx (3 hunks)
  • frontend/src/components/GeneralCompliantComponent.tsx (1 hunks)
  • frontend/src/components/Header.tsx (4 hunks)
  • frontend/src/components/InfoBlock.tsx (1 hunks)
  • frontend/src/components/ItemCardList.tsx (2 hunks)
  • frontend/src/components/LoadingSpinner.tsx (1 hunks)
  • frontend/src/components/LoginPageContent.tsx (1 hunks)
  • frontend/src/components/LogoCarousel.tsx (3 hunks)
  • frontend/src/components/MetricsCard.tsx (1 hunks)
  • frontend/src/components/MetricsScoreCircle.tsx (1 hunks)
  • frontend/src/components/Modal.tsx (3 hunks)
  • frontend/src/components/ModeToggle.tsx (1 hunks)
  • frontend/src/components/ModuleCard.tsx (1 hunks)
  • frontend/src/components/ModuleForm.tsx (11 hunks)
  • frontend/src/components/MultiSearch.tsx (3 hunks)
  • frontend/src/components/NavButton.tsx (1 hunks)
  • frontend/src/components/NavDropDown.tsx (1 hunks)
  • frontend/src/components/Pagination.tsx (3 hunks)
  • frontend/src/components/ProgramForm.tsx (9 hunks)
  • frontend/src/components/ProjectsDashboardNavBar.tsx (1 hunks)
  • frontend/src/components/RecentReleases.tsx (2 hunks)
  • frontend/src/components/RepositoriesCard.tsx (1 hunks)
  • frontend/src/components/ScrollToTop.tsx (1 hunks)
  • frontend/src/components/Search.tsx (1 hunks)
  • frontend/src/components/SearchPageLayout.tsx (1 hunks)
  • frontend/src/components/SingleModuleCard.tsx (1 hunks)
  • frontend/src/components/SnapshotCard.tsx (1 hunks)
  • frontend/src/components/SortBy.tsx (1 hunks)
  • frontend/src/components/ToggleableList.tsx (1 hunks)
  • frontend/src/components/TopContributorsList.tsx (1 hunks)
  • frontend/src/components/TruncatedText.tsx (1 hunks)
  • frontend/src/components/UserCard.tsx (2 hunks)
  • frontend/src/components/UserMenu.tsx (3 hunks)
  • frontend/src/components/skeletons/ApiKeySkelton.tsx (3 hunks)
  • frontend/src/components/skeletons/Card.tsx (4 hunks)
  • frontend/src/components/skeletons/UserCard.tsx (1 hunks)
  • frontend/tailwind.config.js (2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/components/LoginPageContent.test.tsx
📚 Learning: 2025-07-12T17:14:28.536Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/[programKey]/edit/page.tsx:90-128
Timestamp: 2025-07-12T17:14:28.536Z
Learning: Both ProgramForm (programCard.tsx) and ModuleForm (mainmoduleCard.tsx) components already implement HTML validation using the `required` attribute on form fields. The browser's native validation prevents form submission and displays error messages when required fields are empty, eliminating the need for additional JavaScript validation before GraphQL mutations.

Applied to files:

  • frontend/src/components/ProgramForm.tsx
  • frontend/src/components/ModuleForm.tsx
📚 Learning: 2025-04-30T13:41:20.846Z
Learnt from: codic-yeeshu
PR: OWASP/Nest#1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.

Applied to files:

  • frontend/src/components/UserMenu.tsx
🧬 Code graph analysis (3)
frontend/src/components/UserCard.tsx (1)
backend/apps/mentorship/api/internal/nodes/mentor.py (2)
  • name (18-20)
  • login (23-25)
frontend/src/components/RepositoriesCard.tsx (1)
frontend/src/components/TruncatedText.tsx (1)
  • TruncatedText (3-45)
frontend/src/components/Footer.tsx (2)
frontend/src/utils/constants.ts (1)
  • footerSections (52-104)
frontend/src/types/section.ts (1)
  • Section (3-6)
🔇 Additional comments (70)
frontend/src/components/ItemCardList.tsx (1)

61-61: Tailwind v4 rename LGTM; no legacy flex-shrink utilities remain
Repo-wide search confirmed zero instances of flex-shrink-*.

frontend/src/components/InfoBlock.tsx (1)

30-30: LGTM — class reorder only.

No behavioral or Tailwind v4 implications here.

frontend/src/components/MetricsCard.tsx (1)

42-42: Gradient util correctly migrated to v4.

bg-linear-to-br is the v4 direction utility (replacement for bg-gradient-to-br). Looks good with from-/to- stops. (tailwindcss.com)

frontend/src/app/global-error.tsx (1)

43-43: LGTM — class order change only.

No functional or styling change.

frontend/src/components/NavDropDown.tsx (1)

69-69: LGTM — positional class reorder only.

Absolute positioning remains identical.

frontend/src/app/about/page.tsx (2)

109-109: LGTM: heading class reorder is a no-op.

Order-insensitive utilities; no functional change.


144-145: Good v4 migration from space-y to flex + gap.

Switching to flex flex-col gap-3 avoids the v4 space-* behavioral changes and is the recommended pattern. (github.com)

frontend/src/app/snapshots/page.tsx (1)

66-66: Prefer explicit alignment and confirm custom token

  • Replace justify-normal with justify-start for clarity and convention.
  • Verify that text-text is defined in your Tailwind theme (e.g. in tailwind.config.js); no CSS definition was found in automated searches.
frontend/src/app/projects/dashboard/metrics/page.tsx (1)

162-163: LGTM: migrate from space-x to gap with explicit direction.

flex flex-row gap-2 aligns with v4 guidance and avoids space-* pitfalls. (github.com)

frontend/src/components/GeneralCompliantComponent.tsx (1)

30-33: Class reordering is fine; no functional impact.

frontend/src/components/SnapshotCard.tsx (2)

14-16: Class order change is harmless.


14-14: text-balance is supported out of the box in Tailwind v4.1+
Tailwind CSS v4 core (since v4.1) ships the text-balance utility by default, so no additional plugin configuration is required. (tailwindcss.com)

frontend/src/components/RecentReleases.tsx (2)

54-56: Good Tailwind v4 update: flex-shrink-0shrink-0.


67-67: Heading class reorder is OK.

frontend/src/components/SearchPageLayout.tsx (1)

43-43: LGTM — class reordering only; justify-normal is valid in v4.

Reference: Tailwind v4 justify-content docs. (v4-test.tailwindcss.com)

frontend/src/app/snapshots/[id]/page.tsx (1)

113-114: Good v4 migration: shadow-smshadow-xs.
Matches the v3→v4 shadow scale rename.

Reference: v4 default shadow scale changes. (v3.tailwindcss.com)

frontend/src/components/ModeToggle.tsx (1)

25-25: LGTM — focus-visible:outline-hidden aligns with the v4 change from outline-none.

Reference: Tailwind v4 outline update. (github.com)

frontend/src/components/UserCard.tsx (2)

26-26: LGTM: gap migration is correct.

flex flex-col + gap-4 preserves vertical spacing; other class reorders are no-ops.


41-61: Class reorders only — no behavior change.

Typography and color utilities were only reordered; semantics unchanged.

frontend/src/components/SingleModuleCard.tsx (1)

82-82: LGTM: class reordering only.

No visual/behavioral regression expected.

frontend/__tests__/unit/components/Search.test.tsx (2)

338-339: Correct v4 migration: outline utility.

focus:outline-hidden is the right replacement for v3’s focus:outline-none and preserves the accessibility-friendly hidden outline. ✔️ (v3.tailwindcss.com)


354-355: Clear button focus style updated correctly.

Using focus:outline-hidden here aligns with Tailwind v4’s outline changes and keeps ring styles intact. (v3.tailwindcss.com)

frontend/src/components/ModuleCard.tsx (1)

77-77: shadow scale updated correctly for v4.

Switching base shadow from shadow-sm to shadow-xs matches the v3→v4 renaming to preserve prior intensity. (v3.tailwindcss.com, v4-test.tailwindcss.com)

frontend/src/components/LoadingSpinner.tsx (1)

16-16: Class order-only change.

Reordering utilities is no-op; spinner behavior/styles remain the same.

frontend/src/components/Pagination.tsx (1)

61-66: Spacing/min-width migrations look good.

  • space-y-3flex flex-col gap-3 is consistent with v4 best practices.
  • min-w-[2.5rem]min-w-10 uses the numeric min-width API in v4 (min-w-<number>), keeping the same 2.5rem width. (tailwindcss.cms.im)

Also applies to: 85-90, 99-100

frontend/src/components/Modal.tsx (2)

23-23: Backdrop blur token updated correctly.

backdrop-blur-smbackdrop-blur-xs matches the v4 blur scale shift. (tailwindcss.com, v3.tailwindcss.com)


35-36: Header spacing refactor is fine.

Replacing space-x-2 with flex … gap-2 aligns with v4 spacing patterns without changing layout.

frontend/src/components/LogoCarousel.tsx (3)

31-31: Good swap to shrink-0.

Alias is v4-preferred and keeps intent.


25-27: animate-scroll confirmed in frontend/tailwind.config.js (custom keyframes and animation still defined); no changes required.


56-56: Design tokens verified. The muted-foreground, primary (and primary-foreground) colors are defined in tailwind.config.js under theme.extend.colors and the corresponding CSS variables (--muted-foreground, --primary, --primary-foreground) exist in globals.css, so the text-muted-foreground and text-primary classes will not be no-ops.

frontend/src/components/RepositoriesCard.tsx (1)

48-48: LGTM on gap-based layout.

Switch from space-y to flex+gap aligns with v4 and is clearer.

frontend/__tests__/unit/components/LoginPageContent.test.tsx (1)

466-481: Test update matches component change.

Expectations for flex, flex-col, gap-6 are correct and order-agnostic via toHaveClass.

frontend/src/components/ProgramForm.tsx (2)

61-61: LGTM on gap migration.

Consistent with v4 guidelines; improves readability and avoids margin-collapsing pitfalls.

Also applies to: 64-64, 101-101, 153-153


54-54: Validate text-text and justify-normal
text-text is defined under theme.extend.colors.text in frontend/tailwind.config.js.
• Tailwind v4 includes a .justify-normal utility (maps to justify-content: normal) so no fallback needed.

frontend/src/components/MultiSearch.tsx (5)

229-233: Non-functional class reordering looks good.

Absolute positioning + translate combo remains correct for vertically centering the icon.


234-241: Tailwind v4 focus outline update looks correct.

Switch to focus:outline-hidden is consistent with the migration and preserves the custom ring focus styles.


244-249: Clear-button positioning change is safe.

Order-only reflow; no behavioral impact.


252-253: Skeleton class order change is fine.

Selector-based tests should still pass since they match by class presence, not order.


277-281: Alias update to shrink-0 is appropriate.

Matches Tailwind conventions; no layout regression expected.

frontend/src/components/UserMenu.tsx (2)

39-42: Loading spinner class reordering is harmless.

Keeps the same visuals; no action needed.


88-92: Dropdown container class order change is OK.

No functional difference; tests reflect the new order-agnostic checks.

frontend/__tests__/unit/components/UserMenu.test.tsx (1)

692-696: Expectation updated to focus:outline-hidden matches component.

Alignment with Tailwind v4 migration looks good.

frontend/src/app/page.tsx (3)

139-156: Hero spacing tweak is fine.

sm:mb-20 → sm:mb-10 and minor class reordering are benign.


212-244: space-y → flex/gap migration LGTM.

Switching to flex flex-col gap-* is consistent with Tailwind v4 patterns.

Also applies to: 254-284


372-390: CTA section margin reorder is OK.

No functional impact.

frontend/src/components/skeletons/Card.tsx (4)

46-51: Description spacing refactor looks good.

space-y-3 → flex-col gap-3 is consistent with the repo-wide change.


60-61: Avatar skeleton class order change is safe.

No behavior change.


65-72: Social row gap refactor LGTM.

flex-row gap-2 improves clarity.


20-20: Verify default border color after replacing border-borderborder
Tailwind’s .border utility now only sets width; default border‐color is currentColor. The global compatibility override was removed—though --border is defined in :root, it isn’t applied by default. Manually verify visuals and reintroduce a default border‐color override (e.g.

*, ::before, ::after { border-color: var(--border); }

) or use an explicit border-border utility where needed.

frontend/src/components/ModuleForm.tsx (1)

57-57: Remove outdated verification: text-text is properly defined
The text-text utility maps to the CSS variable --text, which is declared in frontend/src/app/globals.css (:root { --text: #000; … }) and exposed via extend.colors.text: 'var(--text)' in frontend/tailwind.config.js. No changes needed.

frontend/src/components/Footer.tsx (4)

23-25: Container spacing updates are fine.

Gap reduction and class reordering are harmless.


27-33: Heading button focus styles OK for v4.

Using focus:outline-hidden with a ring is the correct v4 pattern.
Tailwind v4 introduced outline-hidden as the replacement for the old outline-none behavior. (tailwindcss.com)


47-50: Section content spacing refactor LGTM.

space-y → flex-col gap-2 is consistent.


72-85: Social icons row refactor LGTM.

flex-row gap-6 with centered layout reads better.

frontend/src/components/NavButton.tsx (1)

24-25: Focus-visible outline migration is correct.

focus-visible:outline-hidden aligns with Tailwind v4; you also provide a visible ring, which preserves a11y.
Docs: outline-hidden replaces the old outline-none semantics in v4. (tailwindcss.com)

frontend/__tests__/unit/components/NavButton.test.tsx (1)

216-219: Correct Tailwind v4 focus utility update

Switching expectations to focus-visible:outline-hidden is the right v4 migration from outline-none. Looks good. (github.com)

Also applies to: 326-327

frontend/tailwind.config.js (2)

73-74: Optional: prefer CSS-first plugin registration in v4

Consider moving plugin setup to CSS for consistency with v4 (keeps all Tailwind wiring in styles):
[ suggest_optional_refactor ]
Example in your global CSS:

@import "tailwindcss";
@plugin "tailwindcss-animate";

This complements or replaces JS-config plugins per v4’s compatibility directives. (tailwindcss.com)


5-9: No action needed; Tailwind config is already loaded
globals.css includes @config '../../tailwind.config.js'; on line 3, so the v4 JS config is applied.

frontend/src/components/Card.tsx (1)

132-133: LGTM: spacing refactor to gap-based layout

Switch to gap-3 and responsive sm:gap-0 improves consistency with the broader v4 migration.

frontend/src/components/MetricsScoreCircle.tsx (2)

51-52: LGTM: updated gradient utility to v4 syntax

bg-linear-to-br with from/to stops is valid in v4 and replaces the v3 bg-gradient-to-*. (tailwindcss.com)


63-64: LGTM: class reordering is non-functional

Only order changed; behavior remains identical.

frontend/src/components/Header.tsx (1)

136-137: LGTM: v4-safe focus treatment

focus:outline-hidden is the correct replacement for outline-none in v4 to keep accessible outlines behavior. (github.com)

frontend/src/app/globals.css (2)

1-3: Approve v4 import/config wiring
PostCSS is already configured with @tailwindcss/postcss in frontend/postcss.config.js, so the v4 setup is correct.


199-203: No action needed: bg-background and text-foreground tokens are defined
The extend.colors section in frontend/tailwind.config.js includes

background: 'var(--background)',
foreground: 'hsl(var(--foreground))',

so the bg-background and text-foreground utilities will compile successfully.

frontend/src/app/settings/api-keys/page.tsx (3)

219-221: space-y → flex+gap migration looks correct

Wrapper is now a flex column with gap-4, which is the recommended pattern in v4 vs. relying on space-* in many cases. (github.com)


267-285: LGTM on usage section layout

Switch to flex flex-col gap-4 is consistent with v4 spacing behavior changes. (github.com)


293-329: Modal (new key) content spacing: good

Gap-based vertical rhythm reads well and avoids space-y-* edge cases in v4. (github.com)

frontend/src/components/skeletons/ApiKeySkelton.tsx (3)

26-30: Correct shadow scale update

shadow-smshadow-xs preserves the previous visual weight under v4’s renamed scales. (v3.tailwindcss.com)


81-86: Consistent shadow scale in API Usage skeleton

Also correctly updated to shadow-xs. (v3.tailwindcss.com)


83-89: space-y → flex+gap for skeleton: good

The gap-based structure avoids v4 space-* margin interactions. (github.com)

@kasya kasya marked this pull request as draft August 29, 2025 02:07
Copy link
Contributor

@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: 10

Caution

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

⚠️ Outside diff range comments (3)
frontend/src/components/ModuleForm.tsx (1)

281-285: Don’t throw inside debounced async; fix Error ctor misuse

new Error(message, err) is invalid, and throwing inside the debounced fetch creates unhandled promise rejections in effects. Log and surface a user-facing error instead.

       } catch (err) {
         setRawResults([])
         setShowSuggestions(false)
-        throw new Error('Error fetching suggestions:', err)
+        console.error('Error fetching suggestions', err)
+        setError('Failed to fetch projects. Please try again.')
       }
frontend/src/app/settings/api-keys/page.tsx (2)

296-332: Add accessible label to the “show/hide key” icon button

Screen readers need an aria-label describing the action. Also, consider unifying copy text with the earlier toast for consistency.

- <Button
-   variant="light"
-   size="sm"
-   onPress={() => setShowNewKey(!showNewKey)}
-   isIconOnly
- >
+ <Button
+   variant="light"
+   size="sm"
+   onPress={() => setShowNewKey(!showNewKey)}
+   isIconOnly
+   aria-label={showNewKey ? 'Hide API key' : 'Show API key'}
+ >

To keep the user-facing copy consistent, consider extracting a single message and using it both here and in the creation toast:

// e.g. const COPY_ONCE_MSG = "Important: Copy it now as you won't be able to see it again.";

Then reuse COPY_ONCE_MSG at the toast (Lines 54–57) and here (Line 302).


333-381: Validate newKeyExpiry in handleCreateKey to prevent past dates
Insert the following check before constructing variables (around line 108) in handleCreateKey():

const chosen = new Date(newKeyExpiry);
const today = new Date();
today.setHours(0,0,0,0);
if (Number.isNaN(chosen.getTime()) || chosen < today) {
  addToast({ title: 'Error', description: 'Expiration must be today or later', color: 'danger' });
  return;
}

Also consider enforcing a maximum (e.g., ≤ 1 year) if required by policy.

♻️ Duplicate comments (2)
frontend/src/app/globals.css (1)

5-14: Border default changed: audit for implicit border usages

Good to drop the global override. Please audit components relying on bare border and add explicit border-* colors to keep v3 visuals. See prior bot note; same concern still applies.

frontend/src/components/ModuleForm.tsx (1)

81-81: Focus styles now visible — resolves prior a11y concern

Adding rings/border colors with focus:outline-hidden addresses the earlier “hidden focus” issue.

Also applies to: 96-96, 118-118, 132-132, 144-144, 172-172, 186-186, 214-214, 357-357

🧹 Nitpick comments (9)
frontend/src/app/globals.css (2)

330-345: Dropdown hover: enable pointer-events for better hover/leave behavior

Prevent accidental re-entry flicker by disabling pointer events while hidden.

Apply:

   .dropdown-menu {
-    @apply absolute top-full left-0 mt-2 w-48 rounded-lg bg-white p-3 shadow-lg dark:bg-gray-800;
-    @apply invisible opacity-0 transition-all duration-200 ease-in-out;
+    @apply absolute top-full left-0 mt-2 w-48 rounded-lg bg-white p-3 shadow-lg dark:bg-gray-800;
+    @apply invisible opacity-0 pointer-events-none transition-all duration-200 ease-in-out;
     @apply flex flex-col gap-2;
   }
 
   .dropdown:hover .dropdown-menu {
-    @apply visible opacity-100;
+    @apply visible opacity-100 pointer-events-auto;
   }

205-209: Place CSS variables under base layer

:root { --map-tiles-filter: ... } belongs in base, not utilities, to ensure predictable precedence.

Optional move to:

@layer base {
  :root { --map-tiles-filter: brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.7); }
}
frontend/src/components/MultiSearch.tsx (1)

255-287: Optional a11y: Markup the suggestions as a listbox with options

Improves SR navigation and communicates selection state.

Apply this diff to the container:

-          <div className="absolute z-10 mt-1 w-full overflow-hidden rounded-md border-1 border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800">
+          <div id="multi-search-listbox" role="listbox" className="absolute z-10 mt-1 w-full overflow-hidden rounded-md border-1 border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800">

And update each option:

-                    <li
+                    <li
+                      role="option"
+                      aria-selected={highlightedIndex?.index === index && highlightedIndex?.subIndex === subIndex}
                       key={subIndex}

Outside this hunk, also enhance the input (for completeness):

// On the <input …> element:
role="combobox"
aria-autocomplete="list"
aria-expanded={showSuggestions}
aria-controls="multi-search-listbox"
frontend/src/components/ModuleForm.tsx (2)

57-57: Verify custom token and drop redundant utility

  • Confirm text-text exists in the v4 theme (or CSS variables) after the migration.
  • justify-normal is redundant; remove it.
-    <div className="text-text flex w-full flex-col items-center justify-normal p-5">
+    <div className="text-text flex w-full flex-col items-center p-5">

81-81: Add ring-offset color for dark/light parity

Set offset color to match the field background to avoid a white halo in dark mode.

- className="... focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:border-blue-500 dark:... dark:focus:ring-blue-400 dark:focus:border-blue-400"
+ className="... focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50 focus:border-blue-500 dark:... dark:focus:ring-blue-400 dark:focus:ring-offset-gray-800 dark:focus:border-blue-400"

Apply the same addition on Lines 81, 96, 118, 132, 144, 172, 186, 214.

Also applies to: 96-96, 118-118, 132-132, 144-144, 172-172, 186-186, 214-214

frontend/src/app/settings/api-keys/page.tsx (1)

207-207: Prefer Button props over hard-coded colors for theme consistency

Using Tailwind bg/hover/disabled classes on a design-system Button can drift from the tokenized theme. Prefer the component props (e.g., color="primary" | variant="solid") and keep className minimal (radius, layout) to avoid style conflicts, especially after Tailwind upgrades.

- className="rounded bg-black font-medium text-white transition-colors hover:bg-gray-900/90 disabled:bg-gray-300 disabled:text-gray-500"
+ className="rounded font-medium"
frontend/src/components/Header.tsx (3)

111-111: Nit: justify-normal is redundant

Default justify is already “normal”; consider dropping it for brevity.

Apply:

-<div className="flex items-center justify-normal gap-4">
+<div className="flex items-center gap-4">

136-136: Correct upgrade: use of focus:outline-hidden in v4

This is the right replacement for v3’s outline-none. Consider focus-visible:outline-hidden for better a11y.

-className="bg-transparent text-slate-300 hover:bg-transparent hover:text-slate-100 focus:outline-hidden"
+className="bg-transparent text-slate-300 hover:bg-transparent hover:text-slate-100 focus-visible:outline-hidden"

References: v4 renames outline-noneoutline-hidden and changes semantics. (tailwindcss.com, github.com)

Additionally (outside this line range), add ARIA to improve accessibility:

<Button
  onPress={toggleMobileMenu}
  aria-controls="mobile-drawer"
  aria-expanded={mobileMenuOpen}
  ...
/>

150-150: Remove redundant transform; add IDs/ARIA for the drawer

transform is unnecessary when using translate utilities; drop it. Also give the drawer an id and ARIA to pair with the button.

-          'bg-owasp-blue fixed inset-y-0 left-0 z-50 w-64 transform shadow-md transition-transform dark:bg-slate-800',
+          'bg-owasp-blue fixed inset-y-0 left-0 z-50 w-64 shadow-md transition-transform dark:bg-slate-800',

Reference: transform utilities work without the transform class since Tailwind v3+. (v3.tailwindcss.com)

Outside this line range, consider:

<div
  id="mobile-drawer"
  role="dialog"
  aria-modal="true"
  aria-label="Main menu"
  className={cn(/* same classes as above */)}
>

And update the outside-click selector to the new #mobile-drawer for robustness:

const sidebar = document.getElementById('mobile-drawer')
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e40542b and 8db3df4.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (23)
  • frontend/package.json (1 hunks)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/src/app/settings/api-keys/page.tsx (7 hunks)
  • frontend/src/app/snapshots/[id]/page.tsx (2 hunks)
  • frontend/src/components/ActionButton.tsx (1 hunks)
  • frontend/src/components/Card.tsx (4 hunks)
  • frontend/src/components/Footer.tsx (3 hunks)
  • frontend/src/components/Header.tsx (5 hunks)
  • frontend/src/components/ItemCardList.tsx (2 hunks)
  • frontend/src/components/LoadingSpinner.tsx (1 hunks)
  • frontend/src/components/MetricsCard.tsx (1 hunks)
  • frontend/src/components/Modal.tsx (3 hunks)
  • frontend/src/components/ModuleCard.tsx (1 hunks)
  • frontend/src/components/ModuleForm.tsx (11 hunks)
  • frontend/src/components/MultiSearch.tsx (3 hunks)
  • frontend/src/components/Pagination.tsx (3 hunks)
  • frontend/src/components/ProgramForm.tsx (9 hunks)
  • frontend/src/components/RecentReleases.tsx (2 hunks)
  • frontend/src/components/RepositoriesCard.tsx (1 hunks)
  • frontend/src/components/Search.tsx (1 hunks)
  • frontend/src/components/skeletons/ApiKeySkelton.tsx (3 hunks)
  • frontend/src/components/skeletons/Card.tsx (4 hunks)
  • frontend/src/components/skeletons/UserCard.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/components/RecentReleases.tsx
🚧 Files skipped from review as they are similar to previous changes (16)
  • frontend/src/components/ItemCardList.tsx
  • frontend/src/components/skeletons/UserCard.tsx
  • frontend/src/components/LoadingSpinner.tsx
  • frontend/package.json
  • frontend/src/components/Modal.tsx
  • frontend/src/components/ProgramForm.tsx
  • frontend/src/components/Pagination.tsx
  • frontend/src/components/MetricsCard.tsx
  • frontend/src/components/skeletons/Card.tsx
  • frontend/src/components/Search.tsx
  • frontend/src/app/snapshots/[id]/page.tsx
  • frontend/src/components/ModuleCard.tsx
  • frontend/src/components/RepositoriesCard.tsx
  • frontend/src/components/Footer.tsx
  • frontend/src/components/Card.tsx
  • frontend/src/components/skeletons/ApiKeySkelton.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-12T17:14:28.536Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/[programKey]/edit/page.tsx:90-128
Timestamp: 2025-07-12T17:14:28.536Z
Learning: Both ProgramForm (programCard.tsx) and ModuleForm (mainmoduleCard.tsx) components already implement HTML validation using the `required` attribute on form fields. The browser's native validation prevents form submission and displays error messages when required fields are empty, eliminating the need for additional JavaScript validation before GraphQL mutations.

Applied to files:

  • frontend/src/components/ModuleForm.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (15)
frontend/src/components/ActionButton.tsx (1)

15-15: Confirm color consistency with brand.

You switched body text to text-blue-600 while keeping border/hover at #1D7BD7. If the brand color is #1D7BD7, align the text color too (or use a themed token).

Option if brand should match:

-    '... bg-transparent text-blue-600 hover:bg-[#1D7BD7] hover:text-white ...'
+    '... bg-transparent text-[#1D7BD7] hover:bg-[#1D7BD7] hover:text-white ...'
frontend/src/app/globals.css (2)

15-19: Correct placement of themed ::selection

Moving the dark selection rule under base is the right call.


87-92: Duplicate, conflicting body color/background rules

You set body colors twice (custom vars at Lines 87–92, Tailwind tokens at Lines 199–203). Keep one source of truth to avoid drift.

Apply:

-  body {
-    background-color: var(--background);
-    color: var(--text);
-    transition: background-color, color;
-  }

[ suggest_essential_refactor ]

Also applies to: 199-203

frontend/src/components/MultiSearch.tsx (5)

234-241: Tailwind v4 migration here looks correct


234-241: Prefer focus-visible for better UX

Consider showing focus styles only for keyboard users:
[ suggest_optional_refactor ]
Apply this diff:

-              className="h-12 w-full rounded-lg border-1 border-gray-300 pr-10 pl-10 text-lg text-black focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:focus:border-blue-300 dark:focus:ring-blue-300"
+              className="h-12 w-full rounded-lg border-1 border-gray-300 pr-10 pl-10 text-lg text-black focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-hidden dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:focus-visible:border-blue-300 dark:focus-visible:ring-blue-300"

Background: v4 changed outline behaviors; focus-visible tends to produce the intended experience. (github.com)


252-253: Skeleton reorder is harmless

Class reordering doesn’t affect visuals; remains a proper loading placeholder.


255-260: Good call adding explicit borders under v4 defaults

Adding border-1/border-gray-200 (and dark variants) compensates for v4’s shift to currentColor as the default border color. (tailwindcss.com)


277-281: Shorthand shrink-0 is fine

Using shrink-0 instead of flex-shrink-0 is idiomatic and equivalent.

frontend/src/components/ModuleForm.tsx (1)

64-66: Flex/gap migration LGTM

Replacing space-y-* with flex + gap is correct for v4 and reads cleaner.

Also applies to: 102-102, 156-156

frontend/src/app/settings/api-keys/page.tsx (3)

219-221: LGTM: space-y → gap migration

Switching to flex + gap aligns with Tailwind v4 guidance and avoids layout issues in newer builds.


270-287: LGTM: usage section spacing

The gap-based stack reads well and matches the rest of the page.


230-236: Replace border-b-1 with a valid Tailwind class
Tailwind v4 doesn’t support border-b-1; use border-b (default 1px) or an arbitrary value like border-b-[1px].

- <tr className="border-b-1 border-b-gray-200 dark:border-b-gray-700">
+ <tr className="border-b border-b-gray-200 dark:border-b-gray-700">

Note: GET_API_KEYS already returns createdAt and expiresAt.

frontend/src/components/Header.tsx (3)

154-154: Mobile layout spacing update looks good

Switch to gap-1 and flex layout is consistent with v4 conventions.


201-201: Active submenu state styles LGTM

Color tokens and dark-mode variants are coherent with v4 palette behavior.


56-56: Resolved: dark mode and owasp-blue token verified
darkMode: 'class' is set in tailwind.config.js and the owasp-blue color token is declared; dark:bg-slate-800 will apply as expected.

Copy link
Contributor

@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: 1

Caution

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

⚠️ Outside diff range comments (2)
frontend/src/components/ModuleForm.tsx (1)

281-285: Bug: new Error called with 2 args; also avoid throwing inside debounced async.

new Error only takes one message; extra arg is ignored and TypeScript will error. Throwing from the debounced callback can cause unhandled rejections. Log and set UI error instead.

-      } catch (err) {
+      } catch (err) {
         setRawResults([])
         setShowSuggestions(false)
-        throw new Error('Error fetching suggestions:', err)
+        console.error('Error fetching suggestions:', err)
+        setError('Failed to fetch project suggestions. Please try again.')
       }
frontend/src/components/Header.tsx (1)

134-145: Add ARIA state to the mobile menu button

Expose the menu state for screen readers.

Apply this diff:

           <Button
             onPress={toggleMobileMenu}
-            className="bg-transparent text-slate-300 hover:bg-transparent hover:text-slate-100 focus:outline-hidden"
+            className="bg-transparent text-slate-300 hover:bg-transparent hover:text-slate-100 focus:outline-hidden"
+            aria-expanded={mobileMenuOpen}
+            aria-controls="mobile-drawer"
           >
-            <span className="sr-only">Open main menu</span>
+            <span className="sr-only">{mobileMenuOpen ? 'Close main menu' : 'Open main menu'}</span>
♻️ Duplicate comments (5)
frontend/src/components/ModuleForm.tsx (3)

81-81: Resolved: visible focus styles added; consider focus-visible.

The added focus ring/border addresses the a11y outline reset. Optional: swap focus: with focus-visible: to avoid showing focus styles on mouse click.

- focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-hidden
+ focus-visible:border-blue-500 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:outline-hidden

Also applies to: 96-96, 118-118, 132-132, 144-144, 172-172, 186-186, 214-214


357-357: Make ProjectSelector input responsive; avoid fixed-width overflow.

Switch to fluid width (and keep clear focus treatment with offset colors).

- 'w-96 rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400'
+ 'w-full max-w-md rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400 dark:focus:ring-offset-gray-800'

221-221: Tailwind v4: border-1 / border-t-1 are invalid — use border / border-t.

These classes won’t emit CSS. Replace with canonical width utilities.

- <div className="border-t-1 border-t-gray-200 pt-8 dark:border-t-gray-700">
+ <div className="border-t border-t-gray-200 pt-8 dark:border-t-gray-700">

- className="rounded-lg border-1 border-gray-200 px-6 py-3 font-medium text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-700"
+ className="rounded-lg border border-gray-200 px-6 py-3 font-medium text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-700"

- className="flex items-center justify-center gap-2 rounded-md border-1 border-sky-600 px-4 py-2 text-sky-600 hover:bg-sky-600 hover:text-white disabled:cursor-not-allowed disabled:border-gray-400 disabled:bg-gray-200 disabled:text-gray-500 dark:disabled:bg-gray-700"
+ className="flex items-center justify-center gap-2 rounded-md border border-sky-600 px-4 py-2 text-sky-600 hover:bg-sky-600 hover:text-white disabled:cursor-not-allowed disabled:border-gray-400 disabled:bg-gray-200 disabled:text-gray-500 dark:disabled:bg-gray-700"

Also applies to: 226-226, 233-233

frontend/src/components/Header.tsx (2)

56-56: Header width class fixed — LGTM

Removal of the invalid max-w-screen utility looks good; w-full already ensures full width.


56-56: Verify dark: variant is configured for v4

Because this file relies on dark:* utilities, ensure your global CSS defines the dark variant via @custom-variant (class strategy). (tailwindcss.com, v4-test.tailwindcss.com)

Run:

#!/bin/bash
# Verify Tailwind v4 dark variant is defined in CSS
rg -nP '@custom-variant\s+dark' -g '**/*.{css,pcss,scss}'
🧹 Nitpick comments (4)
frontend/__tests__/unit/components/Footer.test.tsx (1)

315-323: Assert explicit border colors in Footer tests
Test currently checks for border-t-1 but doesn’t verify the actual color classes applied in Footer.tsx. Add assertions for border-t-slate-300 and dark:border-t-slate-600 in Footer.test.tsx to guard against Tailwind v4’s default color change.

frontend/src/components/ModuleForm.tsx (2)

57-57: Verify justify-normal support and custom token text-text.

  • justify-normal may not be generated depending on your Tailwind v4 config; default flex behavior is start, so you can drop it or use justify-start.
  • Ensure text-text is a defined color token in your theme; otherwise it won’t emit CSS.
- <div className="text-text flex w-full flex-col items-center justify-normal p-5">
+ <div className="text-text flex w-full flex-col items-center justify-start p-5">

265-265: Remove unnecessary ESLint suppression.

You already list [client] in deps; the suppression isn’t needed.

-  // eslint-disable-next-line react-hooks/exhaustive-deps
frontend/src/components/Header.tsx (1)

111-111: Drop redundant justify-normal

justify-normal is the default. Prefer removing it (or use justify-start if you want to be explicit).

Apply this diff:

-        <div className="flex items-center justify-normal gap-4">
+        <div className="flex items-center gap-4">
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8db3df4 and 343478e.

📒 Files selected for processing (10)
  • frontend/__tests__/unit/components/Footer.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/MultiSearch.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/Search.test.tsx (2 hunks)
  • frontend/src/components/Header.tsx (4 hunks)
  • frontend/src/components/ItemCardList.tsx (2 hunks)
  • frontend/src/components/LoadingSpinner.tsx (1 hunks)
  • frontend/src/components/ModuleForm.tsx (11 hunks)
  • frontend/src/components/RecentReleases.tsx (2 hunks)
  • frontend/src/components/skeletons/Card.tsx (4 hunks)
  • frontend/src/components/skeletons/UserCard.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • frontend/tests/unit/components/Search.test.tsx
  • frontend/src/components/RecentReleases.tsx
  • frontend/src/components/skeletons/UserCard.tsx
  • frontend/src/components/LoadingSpinner.tsx
  • frontend/src/components/ItemCardList.tsx
  • frontend/src/components/skeletons/Card.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-12T17:14:28.536Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/[programKey]/edit/page.tsx:90-128
Timestamp: 2025-07-12T17:14:28.536Z
Learning: Both ProgramForm (programCard.tsx) and ModuleForm (mainmoduleCard.tsx) components already implement HTML validation using the `required` attribute on form fields. The browser's native validation prevents form submission and displays error messages when required fields are empty, eliminating the need for additional JavaScript validation before GraphQL mutations.

Applied to files:

  • frontend/src/components/ModuleForm.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (5)
frontend/__tests__/unit/components/Footer.test.tsx (1)

315-323: LGTM: Expecting border-t-1 is correct for Tailwind v4.

border-t-1 is a valid v4 utility (top border width 1px) and aligns with the new numeric width pattern; this change in the test looks good. (tailwindcss.com)

frontend/__tests__/unit/components/MultiSearch.test.tsx (1)

142-156: Approve: Input renders border-1 border-gray-300 as tested
Verified in frontend/src/components/MultiSearch.tsx that the <input>’s className includes both border-1 and border-gray-300, satisfying the unit test.

frontend/src/components/ModuleForm.tsx (1)

64-65: Layout migration to flex/gap is clean.

Consistent vertical rhythm and sectioning. LGTM.

Also applies to: 102-102, 156-156

frontend/src/components/Header.tsx (2)

137-137: focus:outline-hidden is the correct v4 replacement

Good upgrade from the old outline-none behavior; outline-hidden restores the accessible “invisible outline” pattern in v4. (github.com)


155-155: Switch to gap- — LGTM*

Replacing space-y-* with gap-* in flex layouts aligns with Tailwind’s recommended spacing approach.

Copy link
Contributor

@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: 0

Caution

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

⚠️ Outside diff range comments (2)
frontend/src/components/ModuleForm.tsx (2)

281-285: Don’t throw inside debounced async handler; show an error instead

throw new Error('...', err) drops the original error, and throwing from a debounced callback leads to unhandled rejections. Log and surface a user-friendly message instead.

-        setRawResults([])
-        setShowSuggestions(false)
-        throw new Error('Error fetching suggestions:', err)
+        console.error('Error fetching suggestions', err)
+        setRawResults([])
+        setShowSuggestions(false)
+        setError('Failed to load project suggestions. Please try again.')

266-287: Guard against stale responses in debounced search (race condition)

Fast typing can resolve older requests after newer ones and overwrite state. Track the latest query and ignore out-of-date results.

-  const fetchSuggestions = useCallback(
-    debounce(async (query: string) => {
+  const latestQueryRef = useRef('')
+  const fetchSuggestions = useCallback(
+    debounce(async (query: string) => {
+      latestQueryRef.current = query
       if (!query.trim()) {
-        setRawResults([])
-        return
+        setRawResults([])
+        setShowSuggestions(false)
+        return
       }
       try {
         const { data } = await client.query({
           query: SEARCH_PROJECTS,
           variables: { query },
         })
-        setRawResults(data.searchProjects || [])
-        setShowSuggestions(true)
+        if (latestQueryRef.current === query) {
+          setRawResults(data.searchProjects || [])
+          setShowSuggestions(true)
+        }
       } catch (err) {
-        setRawResults([])
-        setShowSuggestions(false)
-        throw new Error('Error fetching suggestions:', err)
+        console.error('Error fetching suggestions', err)
+        setRawResults([])
+        setShowSuggestions(false)
+        setError('Failed to load project suggestions. Please try again.')
       }
     }, 300),
     [client]
   )
🧹 Nitpick comments (3)
frontend/src/components/ModuleForm.tsx (3)

81-81: Add explicit ring-offset colors for visible focus in light/dark

You already added focus rings — great. Specify ring-offset color to ensure the ring stands out against differing backgrounds.

Apply on each affected control (example shown once; repeat at the lines above):

- className="w-full rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400"
+ className="w-full rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50 focus:outline-hidden dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400 dark:focus:ring-offset-gray-800"

Also applies to: 96-96, 118-118, 132-132, 144-144, 172-172, 186-186, 214-214


226-237: Buttons lack visible keyboard focus; add focus-visible styles

Inputs have clear focus, but buttons only have hover styles. Add focus-visible rings for a11y parity.

- className="rounded-lg border border-gray-200 px-6 py-3 font-medium text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-700"
+ className="rounded-lg border border-gray-200 px-6 py-3 font-medium text-gray-600 hover:bg-gray-50 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sky-600 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-700 dark:focus-visible:ring-sky-400"
- className="flex items-center justify-center gap-2 rounded-md border border-sky-600 px-4 py-2 text-sky-600 hover:bg-sky-600 hover:text-white disabled:cursor-not-allowed disabled:border-gray-400 disabled:bg-gray-200 disabled:text-gray-500 dark:disabled:bg-gray-700"
+ className="flex items-center justify-center gap-2 rounded-md border border-sky-600 px-4 py-2 text-sky-600 hover:bg-sky-600 hover:text-white focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-sky-600 disabled:cursor-not-allowed disabled:border-gray-400 disabled:bg-gray-2 00 disabled:text-gray-500 dark:focus-visible:ring-sky-400 dark:disabled:bg-gray-700"

357-357: ProjectSelector: add ring-offset colors to match backgrounds

Match the other inputs for consistent focus contrast in light/dark.

- 'w-full max-w-md rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-hidden sm:w-96 dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400'
+ 'w-full max-w-md rounded-lg border-2 bg-gray-50 px-4 py-3 text-gray-800 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-50 focus:outline-hidden sm:w-96 dark:bg-gray-800 dark:text-gray-200 dark:focus:border-blue-400 dark:focus:ring-blue-400 dark:focus:ring-offset-gray-800'
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 343478e and 73f897d.

📒 Files selected for processing (5)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/src/app/settings/api-keys/page.tsx (7 hunks)
  • frontend/src/components/ActionButton.tsx (1 hunks)
  • frontend/src/components/ModuleForm.tsx (11 hunks)
  • frontend/src/components/MultiSearch.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/components/ActionButton.tsx
  • frontend/src/components/MultiSearch.tsx
  • frontend/src/app/settings/api-keys/page.tsx
  • frontend/src/app/globals.css
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-12T17:14:28.536Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/app/mentorship/programs/[programKey]/edit/page.tsx:90-128
Timestamp: 2025-07-12T17:14:28.536Z
Learning: Both ProgramForm (programCard.tsx) and ModuleForm (mainmoduleCard.tsx) components already implement HTML validation using the `required` attribute on form fields. The browser's native validation prevents form submission and displays error messages when required fields are empty, eliminating the need for additional JavaScript validation before GraphQL mutations.

Applied to files:

  • frontend/src/components/ModuleForm.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
frontend/src/components/ModuleForm.tsx (2)

64-66: Flex/gap layout swap is clean

Replacing legacy space-y-* with flex + gap improves consistency with v4.1. LGTM.


57-57: Verify text-text utility and replace justify-normal with justify-start for clarity

I couldn’t find any definition of the text-text class in your Tailwind config or CSS—please confirm whether this custom utility exists. If it doesn’t, remove it and use explicit semantic classes like text-gray-900 dark:text-gray-100. Also, since justify-normal falls back to the default (flex-start), replace it with justify-start (or drop it) for clearer intent.

Proposed diff:

- <div className="text-text flex w-full flex-col items-center justify-normal p-5">
+ <div className="flex w-full flex-col items-center justify-start p-5 text-gray-900 dark:text-gray-100">

@kasya kasya marked this pull request as ready for review August 29, 2025 03:37
@github-actions github-actions bot added the docker Pull requests that update Docker code label Aug 30, 2025
@sonarqubecloud
Copy link

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@arkid15r arkid15r added this pull request to the merge queue Aug 30, 2025
Copy link
Contributor

@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: 0

♻️ Duplicate comments (3)
frontend/src/app/globals.css (3)

120-137: Move resets to base layer (repeat)

Resets and element defaults belong in @layer base to preserve cascade. This was raised earlier and still applies.

Apply within this hunk:

-  * {
-    margin: 0;
-    padding: 0;
-    box-sizing: border-box;
-  }
-
-  h1 {
-    font-size: clamp(1.5rem, 5vw, 2rem);
-  }
-
-  a {
-    color: #1d7bd7;
-  }
-
-  .navlink {
-    color: inherit;
-  }

Then add (outside this hunk, e.g., after Line 93 or keep with existing base block):

@layer base {
  * { margin: 0; padding: 0; box-sizing: border-box; }
  h1 { font-size: clamp(1.5rem, 5vw, 2rem); }
  a { color: #1d7bd7; }
  .navlink { color: inherit; }
}

211-215: Don’t require both prefers-color-scheme and .dark class (repeat)

If dark mode is class-driven, the media query blocks it on users with light scheme.

-  @media (prefers-color-scheme: dark) {
-    .dark .map-tiles {
-      filter: var(--map-tiles-filter, none);
-    }
-  }
+  .dark .map-tiles {
+    filter: var(--map-tiles-filter, none);
+  }

226-228: Leaflet attribution must remain visible (license compliance) (repeat)

Hiding attribution is likely a license violation. Remove the rule and ensure visible attribution.

-  .leaflet-control-attribution {
-    display: none !important;
-  }
🧹 Nitpick comments (4)
frontend/docker/Dockerfile.e2e.test (1)

22-22: Pin pnpm to repo version in the e2e Dockerfile
Your packageManager field pins [email protected] but the image installs “latest,” risking CI drift. For reproducible builds, add after the COPY:

# Pin pnpm to repo version
RUN --mount=type=cache,target=${NPM_CACHE} \
    npm install --ignore-scripts -g [email protected] --cache ${NPM_CACHE}

Verified no legacy tailwind.config.js references remain.

frontend/docker/Dockerfile (1)

30-30: Pin pnpm to 10.10.0 in install step (frontend/docker/Dockerfile:24)
Swap pnpm for [email protected] to lock to the repo’s version for reproducible builds.

- RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
-     npm install --ignore-scripts -g pnpm --cache ${NPM_CACHE}
+ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
+     npm install --ignore-scripts -g [email protected] --cache ${NPM_CACHE}
frontend/tailwind.config.mjs (1)

58-66: Animation speed may be too aggressive

0.5s marquee-like scroll can read as flicker. Consider a slower default or a CSS variable.

-      animation: {
-        scroll: 'scroll 0.5s linear infinite',
-      },
+      animation: {
+        scroll: 'scroll var(--scroll-speed, 10s) linear infinite',
+      },
frontend/src/app/globals.css (1)

335-345: Prevent pointer capture when menu is hidden

Add pointer-events-none to the hidden state; enable on hover for better UX.

   .dropdown-menu {
-    @apply absolute top-full left-0 mt-2 w-48 rounded-lg bg-white p-3 shadow-lg dark:bg-gray-800;
-    @apply invisible opacity-0 transition-all duration-200 ease-in-out;
+    @apply absolute top-full left-0 mt-2 w-48 rounded-lg bg-white p-3 shadow-lg dark:bg-gray-800;
+    @apply invisible opacity-0 pointer-events-none transition-all duration-200 ease-in-out;
     @apply flex flex-col gap-2;
   }
 
   .dropdown:hover .dropdown-menu {
-    @apply visible opacity-100;
+    @apply visible opacity-100 pointer-events-auto;
   }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 73f897d and d504de2.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • frontend/docker/Dockerfile (1 hunks)
  • frontend/docker/Dockerfile.e2e.test (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/tailwind.config.mjs (2 hunks)
🔇 Additional comments (9)
frontend/package.json (1)

46-46: Tailwind v4 + Dayjs bump LGTM

  • v4.1.12 with @tailwindcss/postcss present, and autoprefixer removed — good.
  • Dayjs patch bump is safe.

Also applies to: 108-108

frontend/docker/Dockerfile.e2e.test (1)

22-22: Copying tailwind.config.mjs is correct

Matches the v4 ESM config.

frontend/docker/Dockerfile (1)

30-30: Switch to tailwind.config.mjs is correct

Aligns builder stage with v4 config.

frontend/tailwind.config.mjs (3)

3-3: Static import of tailwindcss-animate LGTM

Using a direct import avoids dynamic import costs and matches v4 ESM config.


70-70: Plugins array LGTM

heroui() + tailwindcss-animate are correctly registered.


6-6: No MDX files detected; leave content globs unchanged
Search under frontend/src returned no *.mdx files, so the existing globs covering JS/TS files are sufficient.

frontend/src/app/globals.css (3)

15-19: Dark selection styling moved to base — good

Correct layer for theming hooks.


298-310: Fixed: uses custom-spin keyframes

Heatmap loader now references the defined keyframes — good.


1-14: v4 layering and border-compat note LGTM

@import + @config are correct for Tailwind v4; border-compat comment is helpful.

Copy link
Contributor

@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: 1

♻️ Duplicate comments (3)
frontend/src/app/globals.css (3)

120-137: Resets should live in @layer base, not utilities

Prevents purge/order surprises and follows Tailwind layering semantics.

-@layer utilities {
-  * { margin: 0; padding: 0; box-sizing: border-box; }
-  h1 { font-size: clamp(1.5rem, 5vw, 2rem); }
-  a { color: #1d7bd7; }
-  .navlink { color: inherit; }
-}
+@layer base {
+  * { margin: 0; padding: 0; box-sizing: border-box; }
+  h1 { font-size: clamp(1.5rem, 5vw, 2rem); }
+  a { color: #1d7bd7; }
+  .navlink { color: inherit; }
+}

205-215: Dark map tiles: remove media + class double gating

If you gate dark mode via class, the media query is redundant and blocks class-driven theme.

-@layer utilities {
-  @media (prefers-color-scheme: dark) {
-    .dark .map-tiles { filter: var(--map-tiles-filter, none); }
-  }
-}
+@layer utilities {
+  .dark .map-tiles { filter: var(--map-tiles-filter, none); }
+}

226-228: Leaflet attribution hidden — compliance risk

Hiding attribution violates Leaflet/OpenStreetMap requirements. Remove this rule and ensure visible attribution.

-  .leaflet-control-attribution {
-    display: none !important;
-  }
🧹 Nitpick comments (6)
frontend/tailwind.config.mjs (2)

5-7: Consider adding MDX to content globs (if used)

If you render MDX, include it to avoid purge misses.

-export default {
-  content: ['node_modules/@heroui/theme/dist/**/*.{js,jsx,ts,tsx}', 'src/**/*.{js,jsx,ts,tsx}'],
+export default {
+  content: [
+    'node_modules/@heroui/theme/dist/**/*.{js,jsx,ts,tsx}',
+    'src/**/*.{js,jsx,ts,tsx,mdx}'
+  ],

58-66: Marquee speed may be excessive

scroll: 'scroll 0.5s linear infinite' is extremely fast for typical marquee usage. Consider length-based duration or a CSS var to tune speed. Not blocking.

frontend/docker/Dockerfile.e2e.test (1)

22-22: Make config files read-only for parity/hardening

Match builder image by setting 0444 to reduce accidental mutations during tests.

-COPY .pnpmrc next.config.ts postcss.config.js playwright.config.ts tailwind.config.mjs tsconfig.json ./
+COPY --chmod=444 .pnpmrc next.config.ts postcss.config.js playwright.config.ts tailwind.config.mjs tsconfig.json ./
frontend/src/app/globals.css (3)

15-19: Dark selection style — OK; consider adding a light default

Add a base ::selection to keep parity across themes.

 @layer base {
+  ::selection { @apply bg-blue-500 text-white; }
   .dark ::selection {
     @apply bg-blue-500 text-white;
   }
 }

87-92: Duplicate body color rules with conflicting tokens

You set colors twice: once with CSS vars (--text/--background) and again via Tailwind tokens (text-foreground/bg-background). Keep one source of truth and add the transition there.

-  body {
-    background-color: var(--background);
-    color: var(--text);
-    transition: background-color, color;
-  }
+  /* remove duplicate; consolidate below */

And consolidate:

 @layer base {
   body {
-    @apply bg-background text-foreground;
+    @apply bg-background text-foreground transition-colors duration-200;
   }
 }

Also applies to: 199-203


206-209: Place CSS variables in base layer

Variables like --map-tiles-filter are tokens; keep them in base for predictable cascade.

-@layer utilities {
-  :root { --map-tiles-filter: ...; }
-}
+@layer base {
+  :root { --map-tiles-filter: ...; }
+}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 73f897d and d504de2.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • frontend/docker/Dockerfile (1 hunks)
  • frontend/docker/Dockerfile.e2e.test (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/app/globals.css (2 hunks)
  • frontend/tailwind.config.mjs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/package.json
🔇 Additional comments (8)
frontend/docker/Dockerfile (1)

30-30: Tailwind v4 config path update looks good

Switching to tailwind.config.mjs aligns with the v4 ESM config. No issues.

frontend/tailwind.config.mjs (1)

3-7: ESM config + plugins wired for Tailwind v4 — LGTM

Importing tailwindcss-animate and exporting default config with darkMode: 'class' and updated content globs is appropriate.

Also applies to: 70-71

frontend/docker/Dockerfile.e2e.test (2)

22-22: Copying tailwind.config.mjs for E2E is correct

Ensures Playwright container has the v4 config. Good.


22-22: AI summary mismatch (TS file not copied)

The summary mentions copying tailwind.config.ts, but the Dockerfile only copies tailwind.config.mjs. If TS is needed, add it; otherwise, the summary should be corrected.

frontend/src/app/globals.css (4)

1-4: Tailwind v4 bootstrap via @import/@config — LGTM

Correct v4 style entrypoint and config path.


298-310: Spinner now references custom keyframes correctly — LGTM

animation: custom-spin ... matches defined @Keyframes custom-spin.


330-345: Dropdown utilities look fine

Pattern uses @apply for visibility/opacity transitions; OK.


5-14: No implicit border usages lacking color utilities detected. All inspected border classes include explicit color modifiers.

pnpm install --frozen-lockfile --ignore-scripts

COPY --chmod=444 .env .pnpmrc next.config.ts postcss.config.js tailwind.config.js tsconfig.json ./
COPY --chmod=444 .env .pnpmrc next.config.ts postcss.config.js tailwind.config.mjs tsconfig.json ./
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Don’t COPY .env into the image; also fix brittle rm

Copying .env bakes secrets into build layers and cache. In runner, rm .env will fail if the file isn’t present, breaking the build. Stop copying .env and make the removal resilient.

Apply:

-COPY --chmod=444 .env .pnpmrc next.config.ts postcss.config.js tailwind.config.mjs tsconfig.json ./
+COPY --chmod=444 .pnpmrc next.config.ts postcss.config.js tailwind.config.mjs tsconfig.json ./

And:

-RUN mkdir -p /app/.next/cache && chown -R nextjs:nodejs /app/.next/cache && chmod -R 755 /app/.next/cache && rm .env
+RUN mkdir -p /app/.next/cache && chown -R nextjs:nodejs /app/.next/cache && chmod -R 755 /app/.next/cache && rm -f .env

Optionally, if build-time env is required, use BuildKit secrets instead of COPY:

-RUN pnpm run build
+RUN --mount=type=secret,id=env,target=/app/.env pnpm run build

Build with: DOCKER_BUILDKIT=1 docker build --secret id=env,src=.env ...

🤖 Prompt for AI Agents
In frontend/docker/Dockerfile around line 30, the Dockerfile currently copies
.env into the image which bakes secrets into build layers and the subsequent rm
will fail if the file is absent; remove .env from the COPY list so it is not
included in the image, and make the removal command resilient (e.g., use a
non-failing removal method such as rm -f or guard the rm with an existence
check) or better yet, stop attempting to remove .env in the Dockerfile and if
build-time env is required, use BuildKit secrets (docker build --secret ...)
instead of COPY.

Merged via the queue into main with commit f040206 Aug 30, 2025
25 checks passed
@arkid15r arkid15r deleted the upgrade-tailwindcss branch August 30, 2025 01:09
Dishant1804 pushed a commit to Dishant1804/Nest that referenced this pull request Sep 6, 2025
* Upgrade TailwindCSS to v.4

* Update classes

* Update classes and apply Code Rabbit suggestions

* Fix tests

* Apply suggestions

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docker Pull requests that update Docker code frontend frontend-tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade TailwindCSS to v4.1

3 participants