-
-
Notifications
You must be signed in to change notification settings - Fork 337
migrate to react-icons #2869
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
base: main
Are you sure you want to change the base?
migrate to react-icons #2869
Conversation
icons changed: fausers->hiusergroup, sun->mdlightmode, famoon->mddarkmode
WalkthroughSystematically migrates frontend from FontAwesome ( Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/DisplayIcon.tsx (1)
3-51: Tighten types and guard against undefined icons to avoid runtime crashesTwo related issues here:
iconstyping vs usage
DisplayIcondeclaresicons: IconwhereIconis defined as{ [key: string]: IconType }, but in this component you treaticons[item]as a data value:{typeof icons[item] === 'number' ? millify(icons[item], { precision: 1 }) : icons[item]}This is a fundamental type mismatch. The actual data passed (from
Card.tsx) is{ starsCount: 1250, forksCount: 350, ... }— a map of numbers/strings, notIconTypes. Either adjust theIcontype to reflect the real value type (e.g.,Record<string, number | string>), or narrow the prop type for this component to a dedicated metrics type instead of reusing the icon type alias.
IconWrappermay receiveundefinedand crashHere:
<IconWrapper className={iconClassName} icon={ICONS[item as IconKeys]?.icon} />If
itemis not a validIconKeys(for example, if called with an unexpected key),ICONS[item as IconKeys]isundefined, so?.iconyieldsundefinedandIconWrapperattempts to render<undefined />, which throws at runtime. To make this safe, guard before rendering:+ const iconConfig = ICONS[item as IconKeys] + if (!iconConfig) return null // or a fallback UI/log + <Tooltip - content={`${ICONS[item as IconKeys]?.label}`} + content={iconConfig.label} ... > <div className={containerClassName}> <span className="text-gray-600 dark:text-gray-300"> - {typeof icons[item] === 'number' ? millify(icons[item], { precision: 1 }) : icons[item]} + {typeof icons[item] === 'number' + ? millify(icons[item], { precision: 1 }) + : icons[item]} </span> <span> - <IconWrapper className={iconClassName} icon={ICONS[item as IconKeys]?.icon} /> + <IconWrapper className={iconClassName} icon={iconConfig.icon} /> </span> </div> </Tooltip>This also prevents rendering a tooltip with
"undefined"as content when the key is not found.(Note: if you care about showing zeros, consider changing
return icons[item] ? (...) : nullto explicitly check for truthiness to preserve0values, but that's pre-existing behavior.)
🧹 Nitpick comments (27)
frontend/src/components/CalendarButton.tsx (1)
7-7: Remove unused hover state logic.The
isHoveredstate and its event handlers are no longer used after migrating to the staticFaCalendarPlusicon. Previously, hover state switched between two different FontAwesome icons, but that behavior was removed.Apply this diff to clean up the dead code:
-import { useState } from 'react' import { FaCalendarPlus } from 'react-icons/fa6' import type { CalendarButtonProps } from 'types/calendar' import getGoogleCalendarUrl from 'utils/getGoogleCalendarUrl' export default function CalendarButton(props: Readonly<CalendarButtonProps>) { - const [isHovered, setIsHovered] = useState(false) const { event, className = '', iconClassName = 'h-4 w-4', icon, showLabel = false, label = 'Add to Google Calendar', } = props const href = getGoogleCalendarUrl(event) const safeTitle = event.title || 'event' const ariaLabel = `Add ${safeTitle} to Google Calendar` return ( <a href={href} target="_blank" rel="noopener noreferrer" aria-label={ariaLabel} title={ariaLabel} className={className} - onMouseEnter={() => setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} > {icon || <FaCalendarPlus className={iconClassName} />} {showLabel && <span>{label}</span>} </a> ) }Also applies to: 28-29
frontend/src/components/MetricsPDFButton.tsx (2)
23-23: Consider adding error handling for the async PDF fetch.The async onClick handler doesn't catch errors from
fetchMetricsPDF. If the PDF generation fails, users won't receive feedback and the error will be an unhandled promise rejection.Consider wrapping the call with try-catch:
- onClick={async () => await fetchMetricsPDF(path, fileName)} + onClick={async () => { + try { + await fetchMetricsPDF(path, fileName) + } catch (error) { + console.error('Failed to download PDF:', error) + // Optionally show user-facing error notification + } + }}
21-24: Consider adding aria-label for improved accessibility.While the Tooltip provides context on hover, screen reader users may benefit from an explicit
aria-labelon the icon button element.<FaFileArrowDown + aria-label="Download as PDF" className="ml-2 h-7 w-7 cursor-pointer text-gray-500 transition-colors duration-200 hover:text-gray-700" onClick={async () => await fetchMetricsPDF(path, fileName)} />frontend/src/components/SnapshotCard.tsx (1)
20-29: Icon JSX replacement is correct; consider decorative a11y hintThe replacements with
<FaCalendar />and<FaChevronRight />are functionally equivalent to the previous FontAwesome usage and look good. Since these icons are purely decorative (date and “View Snapshot” text already convey meaning), you might want to hide them from screen readers:- <FaCalendar className="mr-1 h-4 w-4" /> + <FaCalendar className="mr-1 h-4 w-4" aria-hidden="true" /> ... - <FaChevronRight className="ml-2 h-4 w-4 transform transition-transform group-hover:translate-x-1" /> + <FaChevronRight + className="ml-2 h-4 w-4 transform transition-transform group-hover:translate-x-1" + aria-hidden="true" + />This keeps the DOM semantics tight while preserving the visual change.
frontend/src/components/Search.tsx (1)
6-6: Migrate icons to FA6 for consistency with the rest of the codebase.The import currently uses
react-icons/fa(Font Awesome 5), but the codebase has predominantly migrated toreact-icons/fa6. WhileFaSearchandFaTimesremain in FA5 in other components (MultiSearch.tsx,Header.tsx), consider updating to FA6 to align with the migration strategy used throughout the project, assuming FA6 equivalents are available.frontend/src/utils/utility.ts (1)
38-45: Fallback social URL icon now a component – verify downstream expectationsSwitching the fallback from a Font Awesome class string to the
FaGlobecomponent is aligned with the react-icons migration. Please make sure:
urlMappings[*].iconis also a React component type (e.g.,IconType) so that the union withFaGlobeis consistent.- The consumer that renders these objects expects
iconto be a component, not a string.If everything downstream already uses react-icons components, this change should be type‑safe and cleaner. Optionally, you could centralize this default (
'Social Links'+FaGlobe) inurlMappingsor a shared constant to avoid duplicating the fallback definition.frontend/src/app/global-error.tsx (1)
43-43: Consider splitting styling improvements into a separate PR.The dark mode styling addition (
dark:bg-slate-800) and text color adjustment appear to be UI refinements separate from the primary PR objective. Per project conventions, migration PRs should remain focused on their core objective without including additional styling or UI improvements.frontend/src/components/LineChart.tsx (1)
4-17: Use type-only import forIconTypefor consistency
IconTypeis only used as a type here. To avoid an unnecessary runtime import and match the pattern used elsewhere in the PR (e.g., DonutBarChart), prefer a type-only import:-import { IconType } from 'react-icons' +import type { IconType } from 'react-icons'The updated
icon?: IconTypeprop and its usage inSecondaryCardotherwise look aligned with the react-icons migration.frontend/src/wrappers/IconWrapper.tsx (1)
1-13: IconWrapper implementation is sound; consider type-only importsThe wrapper correctly treats
iconas anIconTypeand forwards SVG props (includingsize) to the underlying react-icon, which is what you want.Since
ComponentPropsandIconTypeare used only in types, you can tighten imports and avoid runtime overhead with type-only imports:-import { ComponentProps } from 'react' -import { IconType } from 'react-icons' +import type { ComponentProps } from 'react' +import type { IconType } from 'react-icons'Otherwise this abstraction looks good as a single place to standardize icon rendering.
frontend/src/components/LoginPageContent.tsx (1)
7-8: Spinner and GitHub icon migration looks good; optional a11y tweakThe swap to
FaSpinner/FaGithubpreserves layout and behavior. Consider addingaria-hidden="true"to these icons since the adjacent text already conveys status, reducing noise for screen readers.Also applies to: 43-56, 71-77
frontend/src/components/MenteeContributorsList.tsx (1)
5-7: IconWrapper integration is correct; consider a more stable keyPassing the icon component into
IconWrapperand then intoSecondaryCardis consistent and keeps this component’s API clean. Minor nit: ifcontributorscan ever reorder, prefer a stable key such askey={item.login}instead of the array index to avoid unnecessary remounts.Also applies to: 16-19, 21-29, 45-47, 53-75
frontend/src/utils/constants.ts (1)
1-3: Typed footerIcons config looks solidUsing
IconTypefor theiconfield and wiring each entry to its matching URL/label makes the footer social config clear and type-safe. If you want additional safety, you could mark this arrayas constto keep it fully readonly, but that’s optional.Also applies to: 31-36, 37-56
frontend/src/components/Footer.tsx (1)
5-6: Footer chevron + social icon migration is cleanThe new chevron icons hook cleanly into the existing toggle logic, and mapping
footerIconstoSocialIconcomponents keeps the social section nicely data-driven. Nice touch on addingrel="noopener noreferrer"to the external links.Also applies to: 36-41, 70-87
frontend/src/utils/urlIconMappings.ts (1)
1-1: Consider hardeninggetSocialIconagainst invalid URLsThe icon mappings themselves look good and the
IconTypereturn type matches the new usage, butnew URL(url)will throw for relative or malformed inputs. If there’s any chance callers pass non‑absolute URLs, wrapping URL parsing in a small try/catch (and falling back toFaGlobe) would make this helper more robust.Also applies to: 3-22, 24-50
frontend/src/app/organizations/page.tsx (1)
4-4: Checkbutton.icontype expectations vs passing a JSX elementHere
submitButton.iconis a rendered<FaRightToBracket />element. In other parts of the PR, icons are often passed around as icon components and rendered via IconWrapper. IfUserCard’s button prop now expects an icon component (rather than a ReactNode), consider changing this to passFaRightToBracketitself and let the consumer apply sizing/styling for consistency. Otherwise, confirm thatbutton.iconis still typed as a generic ReactNode so this usage stays type‑safe.Also applies to: 31-35
frontend/src/app/projects/page.tsx (1)
4-4: Align project card button icon with shared icon conventionsThe JSX usage of
<FaRightToBracket className="h-4 w-4" />will work ifCard’sbutton.iconremains a ReactNode. If the shared button/card types in this PR have been migrated to accept icon components that are rendered via IconWrapper, consider instead passing the icon component and centralizing size/color there to keep types and patterns consistent across the app.Also applies to: 41-45
frontend/src/app/committees/page.tsx (1)
4-4: Keep committee button icon consistent with other button/icon consumersThis page also passes a rendered
<FaRightToBracket />intosubmitButton.icon. If your shared button/card props now standardize on icon components (rendered by IconWrapper), it may be cleaner to pass the component instead and let the consumer handle sizing. If those props are still ReactNode-based, this is fine as-is; just ensure the typings remain aligned.Also applies to: 32-36
frontend/src/app/members/page.tsx (1)
4-4: Verify member card button icon type vs JSX usageAs with the other listing pages,
submitButton.iconhere is a JSX element. IfUserCard/button props have been tightened to use icon components with IconWrapper elsewhere, consider passing the component instead to avoid type drift and centralize styling. If they remain ReactNode-based, this change is consistent and should be safe.Also applies to: 30-34
frontend/src/app/community/snapshots/[id]/page.tsx (1)
5-5: Snapshot details icons updated correctly; optional DRY opportunityThe switch to
FaRightToBracketfor project/chapter buttons andFaCalendarfor the header dates preserves intent and behavior. If more buttons like this appear elsewhere, you could later extract a shared “View Details” button config, but that’s purely a nicety.Also applies to: 50-51, 79-80, 120-120
frontend/src/app/projects/[projectKey]/page.tsx (1)
7-9: Unify issue icon with the rest of the codebase (FaExclamationCircle vs FaCircleExclamation)Here the issues stat uses
FaExclamationCirclefromreact-icons/fa, while other components in this PR useFaCircleExclamationfromreact-icons/fa6for issues. For consistency and to stick to fa6 everywhere, consider this change:-import { FaExclamationCircle } from 'react-icons/fa' -import { FaCodeFork, FaFolderOpen, FaStar } from 'react-icons/fa6' +import { FaCodeFork, FaFolderOpen, FaStar, FaCircleExclamation } from 'react-icons/fa6' @@ - { - icon: FaExclamationCircle, + { + icon: FaCircleExclamation, value: project.issuesCount, unit: 'Issue', },This keeps the visual language and imports consistent with
RecentIssuesandMilestones.Also applies to: 68-82
frontend/src/components/Header.tsx (1)
8-9: Consider consolidating duplicate imports.Both lines import from
'react-icons/fa'and can be combined into a single import statement for better code organization.Apply this diff to consolidate the imports:
-import { FaRegHeart, FaRegStar } from 'react-icons/fa' -import { FaHeart as FaSolidHeart, FaStar as FaSolidStar, FaBars, FaTimes } from 'react-icons/fa' +import { FaRegHeart, FaRegStar, FaHeart as FaSolidHeart, FaStar as FaSolidStar, FaBars, FaTimes } from 'react-icons/fa'frontend/src/components/NavButton.tsx (1)
16-16: Redundant type intersection.According to
frontend/src/types/button.ts,NavButtonPropsalready includesdefaultIcon: IconTypeandhoverIcon: IconType. The intersection& { defaultIcon: IconType; hoverIcon: IconType }is redundant.-}: NavButtonProps & { defaultIcon: IconType; hoverIcon: IconType }) => { +}: NavButtonProps) => {frontend/src/components/StatusBadge.tsx (1)
83-83: Consider usingIconWrapperfor consistency.Other components in this migration (e.g.,
SecondaryCard,NavButton,ProjectsDashboardDropDown) useIconWrapperfor icon rendering. While direct rendering works, usingIconWrapperhere would maintain consistency across the codebase.+import { IconWrapper } from 'wrappers/IconWrapper' ... - {showIcon && <DisplayIcon className="h-3 w-3" />} + {showIcon && <IconWrapper icon={DisplayIcon} className="h-3 w-3" />}frontend/src/components/MenteeIssues.tsx (1)
3-4: State icon mapping and IconWrapper integration look consistent
getStateIconnow returns react-icons components (FaBug/FaCheckCircle/FaClock), and all usages route throughIconWrapper, which matches the new IconType-based pattern. The empty-state icon selection usingactiveTab === 'open' ? FaBug : FaCheckCirclealso preserves the expected UX.If you want clearer visual distinction for merged vs. other non-open states in the future, you could map
state === 'merged'to a dedicated icon instead of falling through toFaClock.Also applies to: 31-40, 46-49, 61-64
frontend/src/app/page.tsx (1)
7-21: getProjectIcon typing and icon mapping are aligned with react-iconsDeclaring
getProjectIcon(projectType: string): IconTypeand returning the Fa* components directly (FaCode, FaBook, FaFileCode, FaTag) fits the react-icons pattern and works cleanly with consumers likeIconWrapper. The default fallback toFaFileCodefor unknown types is a reasonable choice.If
project.typecan ever be null/undefined from GraphQL, consider tightening its type or guarding before calling.toLowerCase()to avoid a runtime throw in that edge case.Also applies to: 98-111
frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx (1)
228-233: Section icons migrated correctly; consider minor a11y tweak for the unassign icon
FaTagsfor “Labels”,HiUserGroupfor “Assignees” and “Interested Users”,FaCodeBranchas theSecondaryCardicon for “Pull Requests”, andFaPluson the “Assign” buttonare all reasonable replacements and follow the component-based icon usage.
For the icon-only unassign button (Line 296), you already provide a descriptive
aria-labelandtitleon the<button>. To avoid screen readers potentially announcing both the label and the decorative icon, you could mark the icon as hidden:- <FaXmark /> + <FaXmark aria-hidden="true" />This keeps the visual unchanged while tightening accessibility semantics.
Also applies to: 245-256, 296-297, 304-305, 378-381, 422-424
frontend/src/components/CardDetailsPage.tsx (1)
341-354: SocialLinks now correctly renders dynamic react-icons componentsMapping
urlsto:const SocialIcon = getSocialIcon(url) ... <SocialIcon className="h-5 w-5" />works well with
getSocialIcon’sIconTypereturn type, and the anchor’s color classes (text-blue-400+ hover variants) will style the icon via inheritance whileclassName="h-5 w-5"handles sizing. This is a clean replacement for the previous FontAwesomeIcon-based rendering.If there’s any chance
urlscan contain invalid URLs, you might eventually want to hardengetSocialIcon(e.g., try/catch aroundnew URL(url)) to avoid throwing from this map, but that’s pre-existing and not introduced by this migration.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (86)
frontend/__tests__/unit/global-error.test.tsx(1 hunks)frontend/src/app/about/page.tsx(9 hunks)frontend/src/app/board/[year]/candidates/page.tsx(6 hunks)frontend/src/app/chapters/page.tsx(2 hunks)frontend/src/app/committees/[committeeKey]/page.tsx(2 hunks)frontend/src/app/committees/page.tsx(2 hunks)frontend/src/app/community/snapshots/[id]/page.tsx(4 hunks)frontend/src/app/community/snapshots/page.tsx(2 hunks)frontend/src/app/contribute/page.tsx(2 hunks)frontend/src/app/global-error.tsx(1 hunks)frontend/src/app/members/[memberKey]/page.tsx(3 hunks)frontend/src/app/members/page.tsx(2 hunks)frontend/src/app/my/mentorship/page.tsx(3 hunks)frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx(7 hunks)frontend/src/app/organizations/[organizationKey]/page.tsx(2 hunks)frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx(2 hunks)frontend/src/app/organizations/page.tsx(2 hunks)frontend/src/app/page.tsx(12 hunks)frontend/src/app/projects/[projectKey]/page.tsx(2 hunks)frontend/src/app/projects/dashboard/metrics/[projectKey]/page.tsx(9 hunks)frontend/src/app/projects/dashboard/metrics/page.tsx(4 hunks)frontend/src/app/projects/dashboard/page.tsx(4 hunks)frontend/src/app/projects/page.tsx(2 hunks)frontend/src/app/settings/api-keys/page.tsx(7 hunks)frontend/src/components/AnchorTitle.tsx(2 hunks)frontend/src/components/Badges.tsx(2 hunks)frontend/src/components/BarChart.tsx(2 hunks)frontend/src/components/BreadCrumbs.tsx(2 hunks)frontend/src/components/CalendarButton.tsx(2 hunks)frontend/src/components/Card.tsx(4 hunks)frontend/src/components/CardDetailsPage.tsx(9 hunks)frontend/src/components/DashboardCard.tsx(2 hunks)frontend/src/components/DisplayIcon.tsx(4 hunks)frontend/src/components/DonutBarChart.tsx(2 hunks)frontend/src/components/EntityActions.tsx(2 hunks)frontend/src/components/Footer.tsx(3 hunks)frontend/src/components/GeneralCompliantComponent.tsx(2 hunks)frontend/src/components/Header.tsx(5 hunks)frontend/src/components/HealthMetrics.tsx(5 hunks)frontend/src/components/InfoBlock.tsx(3 hunks)frontend/src/components/InfoItem.tsx(4 hunks)frontend/src/components/ItemCardList.tsx(2 hunks)frontend/src/components/Leaders.tsx(2 hunks)frontend/src/components/LineChart.tsx(2 hunks)frontend/src/components/LoginPageContent.tsx(4 hunks)frontend/src/components/MenteeContributorsList.tsx(3 hunks)frontend/src/components/MenteeIssues.tsx(6 hunks)frontend/src/components/MetricsPDFButton.tsx(2 hunks)frontend/src/components/Milestones.tsx(2 hunks)frontend/src/components/Modal.tsx(2 hunks)frontend/src/components/ModeToggle.tsx(2 hunks)frontend/src/components/ModuleCard.tsx(3 hunks)frontend/src/components/MultiSearch.tsx(6 hunks)frontend/src/components/NavButton.tsx(3 hunks)frontend/src/components/NavDropDown.tsx(3 hunks)frontend/src/components/Pagination.tsx(2 hunks)frontend/src/components/ProjectTypeDashboardCard.tsx(1 hunks)frontend/src/components/ProjectsDashboardDropDown.tsx(2 hunks)frontend/src/components/ProjectsDashboardNavBar.tsx(2 hunks)frontend/src/components/RecentIssues.tsx(2 hunks)frontend/src/components/RecentPullRequests.tsx(2 hunks)frontend/src/components/RecentReleases.tsx(2 hunks)frontend/src/components/Release.tsx(2 hunks)frontend/src/components/RepositoryCard.tsx(2 hunks)frontend/src/components/ScrollToTop.tsx(2 hunks)frontend/src/components/Search.tsx(3 hunks)frontend/src/components/SecondaryCard.tsx(2 hunks)frontend/src/components/ShowMoreButton.tsx(2 hunks)frontend/src/components/SingleModuleCard.tsx(3 hunks)frontend/src/components/SnapshotCard.tsx(3 hunks)frontend/src/components/SortBy.tsx(2 hunks)frontend/src/components/StatusBadge.tsx(5 hunks)frontend/src/components/ToggleableList.tsx(3 hunks)frontend/src/components/TopContributorsList.tsx(2 hunks)frontend/src/components/UserCard.tsx(4 hunks)frontend/src/components/UserMenu.tsx(2 hunks)frontend/src/types/button.ts(2 hunks)frontend/src/types/card.ts(3 hunks)frontend/src/types/icon.ts(1 hunks)frontend/src/types/level.ts(1 hunks)frontend/src/utils/constants.ts(2 hunks)frontend/src/utils/data.ts(2 hunks)frontend/src/utils/milestoneProgress.ts(2 hunks)frontend/src/utils/urlIconMappings.ts(1 hunks)frontend/src/utils/utility.ts(2 hunks)frontend/src/wrappers/IconWrapper.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-07-03T03:08:03.290Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1703
File: frontend/src/components/BarChart.tsx:33-46
Timestamp: 2025-07-03T03:08:03.290Z
Learning: In the OWASP Nest project's BarChart component (frontend/src/components/BarChart.tsx), the days and requirements arrays are guaranteed to always have the same length in their use cases, so input validation for array length matching is not needed.
Applied to files:
frontend/src/components/BarChart.tsxfrontend/src/components/ProjectsDashboardNavBar.tsxfrontend/src/components/HealthMetrics.tsxfrontend/src/components/DonutBarChart.tsxfrontend/src/app/projects/dashboard/metrics/[projectKey]/page.tsx
📚 Learning: 2025-06-21T12:21:32.372Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.
Applied to files:
frontend/src/components/BarChart.tsxfrontend/src/components/LineChart.tsxfrontend/src/components/HealthMetrics.tsxfrontend/src/components/DonutBarChart.tsxfrontend/src/app/projects/dashboard/metrics/[projectKey]/page.tsxfrontend/src/app/projects/dashboard/page.tsx
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.
Applied to files:
frontend/src/app/members/page.tsxfrontend/src/utils/milestoneProgress.tsfrontend/src/components/EntityActions.tsxfrontend/src/app/contribute/page.tsxfrontend/src/components/SortBy.tsxfrontend/src/components/SingleModuleCard.tsxfrontend/src/components/CalendarButton.tsxfrontend/src/types/button.tsfrontend/src/components/Modal.tsxfrontend/src/components/Search.tsxfrontend/src/components/DashboardCard.tsxfrontend/src/components/ProjectsDashboardNavBar.tsxfrontend/src/app/committees/[committeeKey]/page.tsxfrontend/src/components/AnchorTitle.tsxfrontend/src/app/community/snapshots/page.tsxfrontend/src/app/chapters/page.tsxfrontend/src/components/Badges.tsxfrontend/src/app/projects/[projectKey]/page.tsxfrontend/src/components/LoginPageContent.tsxfrontend/src/utils/urlIconMappings.tsfrontend/src/components/InfoItem.tsxfrontend/src/components/Pagination.tsxfrontend/src/components/ProjectsDashboardDropDown.tsxfrontend/src/components/Footer.tsxfrontend/src/components/HealthMetrics.tsxfrontend/src/components/RepositoryCard.tsxfrontend/src/app/page.tsxfrontend/src/components/MetricsPDFButton.tsxfrontend/src/components/ModeToggle.tsxfrontend/src/components/StatusBadge.tsxfrontend/src/app/about/page.tsxfrontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsxfrontend/src/components/Header.tsxfrontend/src/components/NavButton.tsxfrontend/src/components/Leaders.tsxfrontend/src/components/UserCard.tsxfrontend/src/components/Card.tsxfrontend/src/components/CardDetailsPage.tsxfrontend/src/components/ModuleCard.tsxfrontend/src/app/organizations/page.tsxfrontend/src/components/ScrollToTop.tsxfrontend/src/app/settings/api-keys/page.tsxfrontend/src/components/GeneralCompliantComponent.tsxfrontend/src/components/MenteeIssues.tsxfrontend/src/app/organizations/[organizationKey]/page.tsxfrontend/src/app/global-error.tsxfrontend/src/components/ShowMoreButton.tsxfrontend/src/components/UserMenu.tsxfrontend/src/app/projects/dashboard/page.tsxfrontend/src/app/community/snapshots/[id]/page.tsxfrontend/src/app/projects/page.tsxfrontend/src/components/RecentIssues.tsxfrontend/src/utils/data.tsfrontend/src/app/committees/page.tsxfrontend/src/utils/constants.tsfrontend/src/app/my/mentorship/page.tsxfrontend/src/components/DisplayIcon.tsxfrontend/src/components/MultiSearch.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/app/board/[year]/candidates/page.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.
Applied to files:
frontend/src/app/members/page.tsxfrontend/src/components/EntityActions.tsxfrontend/src/components/SingleModuleCard.tsxfrontend/src/app/committees/[committeeKey]/page.tsxfrontend/src/app/projects/[projectKey]/page.tsxfrontend/src/components/LoginPageContent.tsxfrontend/src/app/projects/dashboard/metrics/page.tsxfrontend/src/app/page.tsxfrontend/src/app/about/page.tsxfrontend/src/components/Header.tsxfrontend/src/app/organizations/page.tsxfrontend/src/app/organizations/[organizationKey]/page.tsxfrontend/src/app/community/snapshots/[id]/page.tsxfrontend/src/app/committees/page.tsxfrontend/src/app/my/mentorship/page.tsxfrontend/src/app/members/[memberKey]/page.tsx
📚 Learning: 2025-07-09T08:37:10.241Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1718
File: frontend/src/app/projects/dashboard/metrics/page.tsx:96-96
Timestamp: 2025-07-09T08:37:10.241Z
Learning: In the OWASP Nest project's MetricsPage component (frontend/src/app/projects/dashboard/metrics/page.tsx), the sorting dropdown intentionally uses selectionMode="multiple" to allow users to select multiple sorting criteria simultaneously. This enables complex sorting scenarios where users can sort by multiple fields in sequence.
Applied to files:
frontend/src/components/SortBy.tsxfrontend/src/app/projects/dashboard/metrics/page.tsx
📚 Learning: 2025-07-13T11:34:31.823Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.
Applied to files:
frontend/src/components/SingleModuleCard.tsxfrontend/src/app/projects/[projectKey]/page.tsxfrontend/src/components/LoginPageContent.tsxfrontend/src/components/CardDetailsPage.tsxfrontend/src/app/organizations/[organizationKey]/page.tsxfrontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsxfrontend/src/components/UserMenu.tsxfrontend/src/app/my/mentorship/page.tsxfrontend/src/app/members/[memberKey]/page.tsx
📚 Learning: 2025-07-12T17:12:25.807Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/ProgramDetails.test.tsx:35-0
Timestamp: 2025-07-12T17:12:25.807Z
Learning: In React applications, button elements should always have an explicit type attribute (type="button", type="submit", or type="reset") to prevent unintended form submission behavior, even when the button appears to be outside of a form context. The default type is "submit" which can cause unexpected behavior.
Applied to files:
frontend/src/types/button.tsfrontend/src/app/chapters/page.tsxfrontend/src/app/organizations/page.tsxfrontend/src/app/community/snapshots/[id]/page.tsxfrontend/src/app/projects/page.tsxfrontend/src/app/committees/page.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.
Applied to files:
frontend/__tests__/unit/global-error.test.tsx
📚 Learning: 2025-11-17T17:30:42.139Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:169-171
Timestamp: 2025-11-17T17:30:42.139Z
Learning: In the OWASP/Nest frontend tests (PR #2671 context), wrapper functions like `expectChaptersCountEqualsThree` that simply call another helper with a fixed parameter (e.g., `expectChaptersCountEquals(3)`) are intentionally used to avoid arrow function callbacks in `waitFor` calls. This pattern prevents adding nesting depth that would trigger rule typescript:S2004. Example: `await waitFor(expectChaptersCountEqualsThree)` avoids the extra nesting from `await waitFor(() => expectChaptersCountEquals(3))`.
Applied to files:
frontend/__tests__/unit/global-error.test.tsx
📚 Learning: 2025-06-20T16:12:59.256Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/HealthMetrics.tsx:30-30
Timestamp: 2025-06-20T16:12:59.256Z
Learning: In the DetailsCard component (frontend/src/components/CardDetailsPage.tsx), there's a length check before rendering HealthMetrics: `healthMetricsData.length > 0`. This ensures that when HealthMetrics is rendered, the data array has at least one element, making accessing data[0] safe within the HealthMetrics component.
Applied to files:
frontend/src/components/HealthMetrics.tsxfrontend/src/app/projects/dashboard/page.tsx
📚 Learning: 2025-06-20T16:12:59.256Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/HealthMetrics.tsx:30-30
Timestamp: 2025-06-20T16:12:59.256Z
Learning: In the DetailsCard component (frontend/src/components/CardDetailsPage.tsx), there's a safety check that ensures HealthMetrics component is only rendered when healthMetricsData exists and has at least one element: `healthMetricsData && healthMetricsData.length > 0`. This makes accessing data[0] safe within the HealthMetrics component.
Applied to files:
frontend/src/components/HealthMetrics.tsx
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.
Applied to files:
frontend/src/app/projects/dashboard/metrics/[projectKey]/page.tsxfrontend/src/app/community/snapshots/[id]/page.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/app/board/[year]/candidates/page.tsx
📚 Learning: 2025-07-11T15:46:58.233Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/components/UserMenu.tsx:56-60
Timestamp: 2025-07-11T15:46:58.233Z
Learning: In the UserMenu component's handleLogout function, both logout() and signOut() calls are intentionally kept despite the useLogout hook already calling signOut internally, as this is necessary for the specific implementation requirements.
Applied to files:
frontend/src/components/UserMenu.tsx
🧬 Code graph analysis (27)
frontend/src/utils/milestoneProgress.ts (1)
backend/apps/github/api/internal/nodes/milestone.py (1)
progress(40-45)
frontend/src/components/DashboardCard.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/ProjectsDashboardNavBar.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/wrappers/IconWrapper.tsx (1)
frontend/src/types/icon.ts (1)
Icon(2-4)
frontend/src/app/committees/[committeeKey]/page.tsx (1)
backend/apps/owasp/api/internal/queries/committee.py (1)
committee(14-28)
frontend/src/components/Badges.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/app/projects/[projectKey]/page.tsx (1)
backend/apps/github/models/repository.py (1)
project(162-164)
frontend/src/components/InfoItem.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/ProjectsDashboardDropDown.tsx (2)
frontend/src/types/button.ts (1)
Button(4-9)frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/Footer.tsx (2)
frontend/src/utils/constants.ts (1)
footerIcons(31-56)frontend/src/types/link.ts (1)
Link(1-7)
frontend/src/app/projects/dashboard/metrics/page.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/app/page.tsx (4)
frontend/src/components/CalendarButton.tsx (1)
CalendarButton(6-35)frontend/src/utils/dateFormatter.ts (2)
formatDateRange(22-61)formatDate(1-20)frontend/src/components/TruncatedText.tsx (1)
TruncatedText(3-45)frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/StatusBadge.tsx (1)
frontend/src/components/DisplayIcon.tsx (1)
DisplayIcon(7-55)
frontend/src/components/SecondaryCard.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/app/about/page.tsx (3)
backend/apps/github/api/internal/nodes/milestone.py (1)
progress(40-45)frontend/src/utils/aboutData.ts (1)
missionContent(3-8)frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/NavButton.tsx (2)
frontend/src/types/button.ts (1)
NavButtonProps(11-19)frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/Card.tsx (4)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)frontend/src/utils/data.ts (1)
level(61-82)frontend/src/utils/urlIconMappings.ts (1)
getSocialIcon(24-50)frontend/src/types/link.ts (1)
Link(1-7)
frontend/src/components/CardDetailsPage.tsx (1)
frontend/src/utils/urlIconMappings.ts (1)
getSocialIcon(24-50)
frontend/src/components/ModuleCard.tsx (2)
frontend/src/components/InfoItem.tsx (1)
TextInfoItem(37-52)frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/components/Milestones.tsx (1)
frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/components/Release.tsx (1)
frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/app/settings/api-keys/page.tsx (1)
frontend/src/types/button.ts (1)
Button(4-9)
frontend/src/components/GeneralCompliantComponent.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/MenteeIssues.tsx (1)
frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
frontend/src/components/RecentPullRequests.tsx (1)
frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/components/RecentIssues.tsx (1)
frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/components/DisplayIcon.tsx (2)
frontend/src/utils/data.ts (2)
ICONS(36-57)IconKeys(59-59)frontend/src/wrappers/IconWrapper.tsx (1)
IconWrapper(13-13)
🪛 GitHub Check: SonarCloud Code Analysis
frontend/src/app/projects/dashboard/metrics/page.tsx
[warning] 97-97: Extract this nested ternary operation into an independent statement.
frontend/src/components/Header.tsx
[warning] 9-9: 'react-icons/fa' imported multiple times.
[warning] 8-8: 'react-icons/fa' imported multiple times.
|
@sameersharmadev Dec 10 was 3 days ago and it's still in draft 🤷♂️ |
Yeah I'm still kinda new to tests and I dont wanna mess up 😅. Just give me a day I have ~20 test files remaining |



Proposed change
Resolves #2800
This PR migrates all FontAwesome icons to react-icons. All existing FontAwesome imports were replaced with their react-icons equivalents (
react-icons/fa,react-icons/fa6).Icon changes:
FaUsersfrom bothfaandfa6were different from the one we use for some reason, so I usedHiUserGroup(react-icons/hi) instead.faMoon and the custom sun icon were replaced with
MdDarkModeandMdLightMode.Tests for these changes still remain, just wanted to draft a PR first if any changes are needed in the implementation.
Checklist
make check-testlocally and all tests passed