- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 250
Upgrade TailwindCSS to v.4.1.12 #2153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| Summary by CodeRabbit
 WalkthroughTailwindCSS 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
 Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Assessment against linked issues
 Assessment against linked issues: Out-of-scope changes
 Possibly related PRs
 Suggested reviewers
 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 unit tests
 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit: 
 SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type  Other keywords and placeholders
 Status, Documentation and Community
 | 
There was a problem hiding this 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-2is applied to a container with a single child; label is outside.This defeats the purpose of replacing
space-x-2and also doubles spacing viamr-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 utilitytext-align-leftwithtext-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-400with a default Tailwind duration (e.g.,duration-300) or add aduration-400entry undertheme.extend.transitionDurationintailwind.config.js(no customduration-400found in config).
🧹 Nitpick comments (15)
frontend/src/components/GeneralCompliantComponent.tsx (1)
21-21: Remove redundantfilterutility.
drop-shadow-*applies the necessary filter; the standalonefilterclass 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;truncatealready covers them.In v4,
truncatesetsoverflow-hidden,text-ellipsis, andwhitespace-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-hiddenreplaces the v3 behavior formerly provided byoutline-none. Keep it, or optionally scope to keyboard users withfocus-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
Includetype="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 layerUniversal resets (
*,h1,a) belong in@layer baseto 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 a11yHover 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-sm→shadow-xs- frontend/src/app/settings/api-keys/page.tsx (line 207): change
rounded-sm→rounded-xsAudit any other instances of
shadow-sm,rounded-sm, orblur-smand update to the v4 equivalents for consistent styling.frontend/src/components/skeletons/ApiKeySkelton.tsx (1)
9-10: Minor: purely cosmetic class reorderingOnly 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.
⛔ Files ignored due to path filters (1)
- frontend/pnpm-lock.yamlis 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 offlex-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-3avoids the v4space-*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-normalwithjustify-startfor clarity and convention.- Verify that
text-textis 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-2aligns with v4 guidance and avoidsspace-*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-balanceis supported out of the box in Tailwind v4.1+
Tailwind CSS v4 core (since v4.1) ships thetext-balanceutility 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-0→shrink-0.
67-67: Heading class reorder is OK.frontend/src/components/SearchPageLayout.tsx (1)
43-43: LGTM — class reordering only;justify-normalis 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-sm➜shadow-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-hiddenaligns with the v4 change fromoutline-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-4preserves 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-hiddenis the right replacement for v3’sfocus:outline-noneand preserves the accessibility-friendly hidden outline. ✔️ (v3.tailwindcss.com)
354-355: Clear button focus style updated correctly.Using
focus:outline-hiddenhere 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-smtoshadow-xsmatches 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-3→flex flex-col gap-3is consistent with v4 best practices.
min-w-[2.5rem]→min-w-10uses 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-sm→backdrop-blur-xsmatches the v4 blur scale shift. (tailwindcss.com, v3.tailwindcss.com)
35-36: Header spacing refactor is fine.Replacing
space-x-2withflex … gap-2aligns 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. Themuted-foreground,primary(andprimary-foreground) colors are defined in tailwind.config.js undertheme.extend.colorsand the corresponding CSS variables (--muted-foreground,--primary,--primary-foreground) exist in globals.css, so thetext-muted-foregroundandtext-primaryclasses 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-textis defined undertheme.extend.colors.textinfrontend/tailwind.config.js.
• Tailwind v4 includes a.justify-normalutility (maps tojustify-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 replacingborder-border→border
Tailwind’s.borderutility now only sets width; default border‐color iscurrentColor. The global compatibility override was removed—though--borderis 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-borderutility where needed.frontend/src/components/ModuleForm.tsx (1)
57-57: Remove outdated verification:text-textis properly defined
Thetext-textutility maps to the CSS variable--text, which is declared infrontend/src/app/globals.css(:root { --text: #000; … }) and exposed viaextend.colors.text: 'var(--text)'infrontend/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 updateSwitching 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 v4Consider 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 layoutSwitch 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 syntaxbg-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-functionalOnly order changed; behavior remains identical.
frontend/src/components/Header.tsx (1)
136-137: LGTM: v4-safe focus treatmentfocus: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/postcssinfrontend/postcss.config.js, so the v4 setup is correct.
199-203: No action needed:bg-backgroundandtext-foregroundtokens are defined
Theextend.colorssection in frontend/tailwind.config.js includesbackground: 'var(--background)', foreground: 'hsl(var(--foreground))',so the
bg-backgroundandtext-foregroundutilities will compile successfully.frontend/src/app/settings/api-keys/page.tsx (3)
219-221: space-y → flex+gap migration looks correctWrapper is now a flex column with
gap-4, which is the recommended pattern in v4 vs. relying onspace-*in many cases. (github.com)
267-285: LGTM on usage section layoutSwitch to
flex flex-col gap-4is consistent with v4 spacing behavior changes. (github.com)
293-329: Modal (new key) content spacing: goodGap-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-sm→shadow-xspreserves the previous visual weight under v4’s renamed scales. (v3.tailwindcss.com)
81-86: Consistent shadow scale in API Usage skeletonAlso correctly updated to
shadow-xs. (v3.tailwindcss.com)
83-89: space-y → flex+gap for skeleton: goodThe gap-based structure avoids v4
space-*margin interactions. (github.com)
There was a problem hiding this 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 buttonScreen 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: ValidatenewKeyExpiryinhandleCreateKeyto prevent past dates
Insert the following check before constructingvariables(around line 108) inhandleCreateKey():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 implicitborderusagesGood to drop the global override. Please audit components relying on bare
borderand add explicitborder-*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 concernAdding rings/border colors with
focus:outline-hiddenaddresses 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 behaviorPrevent 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 optionsImproves 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-textexists in the v4 theme (or CSS variables) after the migration.
justify-normalis 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 paritySet 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 consistencyUsing 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-normalis redundantDefault 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 offocus:outline-hiddenin v4This is the right replacement for v3’s
outline-none. Considerfocus-visible:outline-hiddenfor 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-none→outline-hiddenand 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 redundanttransform; add IDs/ARIA for the drawer
transformis unnecessary when using translate utilities; drop it. Also give the drawer anidand 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
transformclass 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-drawerfor 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.
⛔ Files ignored due to path filters (1)
- frontend/pnpm-lock.yamlis 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-600while 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 ::selectionMoving the dark selection rule under base is the right call.
87-92: Duplicate, conflicting body color/background rulesYou 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
- focus:outline-hidden is the right replacement for v3’s focus:outline-none. (tailwindcss.com, github.com)
- border-1 and border-b-1 are valid in v4 (generalized border- syntax). (tailwindcss.com)
234-241: Prefer focus-visible for better UXConsider 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 harmlessClass reordering doesn’t affect visuals; remains a proper loading placeholder.
255-260: Good call adding explicit borders under v4 defaultsAdding 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 fineUsing shrink-0 instead of flex-shrink-0 is idiomatic and equivalent.
frontend/src/components/ModuleForm.tsx (1)
64-66: Flex/gap migration LGTMReplacing 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 migrationSwitching to flex + gap aligns with Tailwind v4 guidance and avoids layout issues in newer builds.
270-287: LGTM: usage section spacingThe gap-based stack reads well and matches the rest of the page.
230-236: Replaceborder-b-1with a valid Tailwind class
Tailwind v4 doesn’t supportborder-b-1; useborder-b(default 1px) or an arbitrary value likeborder-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
createdAtandexpiresAt.frontend/src/components/Header.tsx (3)
154-154: Mobile layout spacing update looks goodSwitch to
gap-1and flex layout is consistent with v4 conventions.
201-201: Active submenu state styles LGTMColor 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 theowasp-bluecolor token is declared;dark:bg-slate-800will apply as expected.
There was a problem hiding this 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 Errorcalled with 2 args; also avoid throwing inside debounced async.
new Erroronly 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 buttonExpose 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:withfocus-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-hiddenAlso 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-1are invalid — useborder/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 — LGTMRemoval of the invalid max-w-screen utility looks good; w-full already ensures full width.
56-56: Verify dark: variant is configured for v4Because 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 forborder-t-1but doesn’t verify the actual color classes applied inFooter.tsx. Add assertions forborder-t-slate-300anddark:border-t-slate-600inFooter.test.tsxto guard against Tailwind v4’s default color change.frontend/src/components/ModuleForm.tsx (2)
57-57: Verifyjustify-normalsupport and custom tokentext-text.
justify-normalmay not be generated depending on your Tailwind v4 config; default flex behavior is start, so you can drop it or usejustify-start.- Ensure
text-textis 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-depsfrontend/src/components/Header.tsx (1)
111-111: Drop redundant justify-normaljustify-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.
📒 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-1is 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 rendersborder-1 border-gray-300as tested
Verified in frontend/src/components/MultiSearch.tsx that the<input>’sclassNameincludes bothborder-1andborder-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 replacementGood 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.
There was a problem hiding this 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/darkYou 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 stylesInputs 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 backgroundsMatch 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.
📒 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 cleanReplacing legacy space-y-* with flex + gap improves consistency with v4.1. LGTM.
57-57: Verifytext-textutility and replacejustify-normalwithjustify-startfor clarityI couldn’t find any definition of the
text-textclass in your Tailwind config or CSS—please confirm whether this custom utility exists. If it doesn’t, remove it and use explicit semantic classes liketext-gray-900 dark:text-gray-100. Also, sincejustify-normalfalls back to the default (flex-start), replace it withjustify-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">
| 
 | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
There was a problem hiding this 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)
Swappnpmfor[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 aggressive0.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 hiddenAdd 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.
⛔ Files ignored due to path filters (1)
- frontend/pnpm-lock.yamlis 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 correctMatches the v4 ESM config.
frontend/docker/Dockerfile (1)
30-30: Switch to tailwind.config.mjs is correctAligns builder stage with v4 config.
frontend/tailwind.config.mjs (3)
3-3: Static import of tailwindcss-animate LGTMUsing a direct import avoids dynamic import costs and matches v4 ESM config.
70-70: Plugins array LGTMheroui() + 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 — goodCorrect layer for theming hooks.
298-310: Fixed: uses custom-spin keyframesHeatmap 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.
There was a problem hiding this 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 utilitiesPrevents 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 gatingIf 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 riskHiding 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/hardeningMatch 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 defaultAdd 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 tokensYou 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 layerVariables 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.
⛔ Files ignored due to path filters (1)
- frontend/pnpm-lock.yamlis 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 goodSwitching 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 — LGTMImporting 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 correctEnsures 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 — LGTMCorrect 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 finePattern uses @apply for visibility/opacity transitions; OK.
5-14: No implicitborderusages lacking color utilities detected. All inspectedborderclasses 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 ./ | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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 .envOptionally, 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 buildBuild 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.
* 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]>



Resolves #2074