Skip to content

improved breadcrumbs by introducing page layout component #1515

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

Closed
wants to merge 37 commits into from

Conversation

codic-yeeshu
Copy link
Contributor

Resolves #1425

  • Improved breadcrumbs by introducing a Page Layout component.
  • Instead of showing elements from the URL, we now use props as breadcrumb items.
  • Also modified test cases that were affected by the changes.

Copy link
Contributor

coderabbitai bot commented May 25, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a unified page layout with breadcrumb navigation across all main frontend pages.
    • Enhanced admin interface and scoring logic for OWASP project health metrics.
    • Added robust retry handling for Slack API rate limits in message synchronization.
  • Refactor

    • Standardized and unified frontend type definitions, replacing snake_case with camelCase and consolidating similar types.
    • Updated component and prop naming for consistency and clarity.
    • Simplified and improved breadcrumb handling in the frontend.
  • Bug Fixes

    • Improved accessibility and specificity in frontend test queries.
    • Fixed field naming and compliance checks in project health metrics.
  • Chores

    • Upgraded various frontend and backend dependencies.
    • Added and updated cron jobs for production and staging environments.
    • Improved spell checker dictionary and linting configurations.
  • Tests

    • Added and refactored comprehensive test suites for new and existing backend and frontend features.
    • Introduced shared test utilities and assertion helpers.
  • Documentation

    • Updated Dockerfiles and Makefiles for clarity and latest Python version support.
  • Style

    • Applied consistent import styles and naming conventions throughout the codebase.

Summary by CodeRabbit

  • New Features

    • Introduced a new layout component that provides consistent page structure and breadcrumb navigation across various pages.
    • Breadcrumbs are now explicitly defined for detail pages, improving navigation clarity.
  • Refactor

    • Updated multiple pages to use the new layout and breadcrumb system for a unified user experience.
    • Breadcrumbs component now relies on provided breadcrumb data instead of deriving it from the URL.
  • Style

    • Adjusted card detail pages to remove the white background in light mode for a more consistent appearance.
  • Tests

    • Improved test reliability and accessibility by using more specific queries and updating test logic to match new breadcrumb handling.
    • Added shared test utilities to simplify and standardize assertions across multiple test suites.
  • Chores

    • Updated configuration files to support new test utility paths and aliases.
    • Converted many imports to type-only imports for improved TypeScript clarity and performance.
    • Renamed and unified types to use camelCase naming conventions and consolidated similar types.

Walkthrough

The BreadCrumbs component was refactored to accept explicit breadcrumb items as props, removing the internal logic for deriving breadcrumbs from the URL. A new PageLayout component was introduced to generate and merge automatic and manual breadcrumbs. All relevant page components were updated to use PageLayout and provide appropriate breadcrumb data. Corresponding tests were updated to match the new interface, using shared assertion helpers for better maintainability. Additionally, many frontend types were unified and converted to camelCase, and imports were changed to type-only imports. The RootLayout component removed direct BreadCrumbs usage, delegating breadcrumb rendering to PageLayout. Minor styling adjustments were made to card components.

Changes

Files/Paths Change Summary
frontend/src/components/BreadCrumbs.tsx Refactored to accept breadcrumbItems prop; removed internal path parsing; added new interfaces.
frontend/src/components/PageLayout.tsx New component for layout and breadcrumb generation/merging; exports interfaces and helpers.
frontend/src/app/**/page.tsx (about, chapters, committees, contribute, members, organizations, projects, repositories, snapshots, users) Wrapped content in PageLayout; provided breadcrumbItems prop where relevant; updated types.
frontend/src/app/layout.tsx Removed BreadCrumbs usage and import; reorganized metadata and favicon configuration.
frontend/src/components/CardDetailsPage.tsx Removed bg-white class from outer div.
frontend/tests/unit/components/BreadCrumbs.test.tsx Refactored tests to pass explicit breadcrumbItems prop; removed pathname mocking.
frontend/tests/unit/pages/*.test.tsx (CommitteeDetails, OrganizationDetails, ProjectDetails, RepositoryDetails, SnapshotDetails, UserDetails) Updated assertions to use getByRole('heading', { name }) for more specific checks.
frontend/tests/testUtils/sharedAssertions.ts Added shared assertion helpers for repo details, headings/texts, and contributor toggling.
frontend/tests/unit/pages/About.test.tsx Refactored contributor toggle test to use shared assertion helper.
frontend/jest.config.ts Added test path ignore pattern and module alias for test utilities.
frontend/tsconfig.json Added path alias for test utilities.
frontend/src/types/**/*.ts Unified and renamed types to camelCase; converted interfaces to type aliases; changed imports to type-only imports.
frontend/src/components/**/*.tsx Converted imports to type-only imports; updated prop names to camelCase and types accordingly.
frontend/src/server/fetchAlgoliaData.ts Removed removeIdxPrefix mapping; changed return type to AlgoliaResponse<T>.
frontend/src/server/utility.ts Removed utility for removing idx_ prefix from keys.
frontend/src/components/ChapterMap.tsx Simplified data handling by removing intermediate mapped array; used direct access with optional chaining.
frontend/src/components/ChapterMapWrapper.tsx Updated geoLocData prop type to unified Chapter[].
frontend/src/components/ContributorAvatar.tsx Unified contributor type to single Contributor type; simplified type guard.
frontend/src/components/TopContributorsList.tsx Renamed component from TopContributors to TopContributorsList; updated prop types.
frontend/src/components/UserCard.tsx Renamed props from snake_case to camelCase; updated imports to type-only.
frontend/src/components/NavButton.tsx Adjusted CSS classes for padding and width; changed import to type-only.
frontend/src/components/Header.tsx Updated GitHub star button icon colors from Tailwind classes to hex color codes.
backend/apps/owasp/management/commands/owasp_update_project_health_metrics.py Added new management command to update OWASP project health metrics in bulk.
backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py Added new management command to calculate and update health metric scores.
backend/apps/owasp/management/commands/owasp_update_project_health_requirements.py Updated command to use update_or_create and added new compliance fields.
backend/apps/owasp/models/project.py Added multiple computed properties for counts and compliance checks related to project health.
backend/apps/owasp/models/project_health_metrics.py Changed model inheritance, field types, added bulk save method, and added date difference properties.
backend/apps/owasp/models/project_health_requirements.py Added new Boolean fields for funding and leader requirements compliance.
backend/apps/owasp/admin.py Added custom admin class for ProjectHealthMetrics with filters, search, and list display.
backend/apps/slack/management/commands/slack_sync_messages.py Added retry logic and max retry argument for Slack API rate limit handling in message sync.
backend/apps/core/utils/index.py Added deep_camelize function to recursively convert dict keys to camelCase.
backend/apps/common/utils.py Added convert_to_camel_case utility function.
frontend/tests/unit/data/*.ts Renamed mock data properties from snake_case to camelCase consistently.
frontend/tests/unit/pages/*.test.ts Refactored tests to use shared assertion helpers and more semantic queries.

Assessment against linked issues

Objective Addressed Explanation
Refactor BreadCrumbs to accept explicit breadcrumb items and improve flexibility (#1425)
Display H1 header content (e.g., full project/user/chapter names) in breadcrumbs for relevant pages (#1425)
Implement changes for all pages using breadcrumbs (#1425)
Add/update simple tests for the new breadcrumbs logic (#1425)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • OWASP/Nest#1397: Refactored the original BreadCrumbs component to derive segments from the pathname; this PR replaces that logic.
  • OWASP/Nest#1435: Fixed breadcrumb styling and added tests that relied on mocking the pathname, which is now changed to explicit props.
  • OWASP/Nest#1550: Related backend work on OWASP project health metrics, management commands, and models that complement frontend health metrics display.

Suggested reviewers

  • kasya
  • arkid15r
  • aramattamara
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

Documentation and Community

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (8)
frontend/src/app/committees/page.tsx (1)

67-67: Consider using optional chaining for cleaner code.

The static analysis tool correctly identifies an opportunity to use optional chaining for more concise code.

-        {committees && committees.map(renderCommitteeCard)}
+        {committees?.map(renderCommitteeCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

86-86: Consider using optional chaining for cleaner code.

Similar to the committees page, this can be simplified with optional chaining.

-        {issues && issues.map(renderContributeCard)}
+        {issues?.map(renderContributeCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

68-68: Simplify conditional rendering with optional chaining.

The static analysis tool correctly identifies that optional chaining would be cleaner here.

Apply this diff to use optional chaining:

-          {organizations && organizations.map(renderOrganizationCard)}
+          {organizations?.map(renderOrganizationCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 68-68: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

67-67: Consider using optional chaining for better defensive programming.

The static analysis tool suggests using optional chaining, which would make the code more robust against potential undefined values.

Apply this diff to use optional chaining:

-          {users && users.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
+          {users?.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

83-83: Consider using optional chaining for consistency and safety.

The static analysis tool suggests using optional chaining, which would be more defensive and consistent with modern JavaScript practices.

Apply this diff to use optional chaining:

-        {projects && projects.filter((project) => project.is_active).map(renderProjectCard)}
+        {projects?.filter((project) => project.is_active).map(renderProjectCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

105-105: Use optional chaining for cleaner code.

The static analysis tool correctly identified that the conditional rendering can be simplified using optional chaining.

Apply this diff to use optional chaining:

-        {chapters && chapters.filter((chapter) => chapter.is_active).map(renderChapterCard)}
+        {chapters?.filter((chapter) => chapter.is_active).map(renderChapterCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

4-7: Consider moving interface to a shared types file.

While the interface definition is correct, consider moving BreadcrumbItem to a shared types file (e.g., types/breadcrumb.ts) for better reusability across components, especially since this interface will likely be used by consuming components.

-interface BreadcrumbItem {
-  title: string
-  href: string
-}

Create frontend/src/types/breadcrumb.ts:

export interface BreadcrumbItem {
  title: string
  href: string
}

Then import it:

+import { BreadcrumbItem } from 'types/breadcrumb'
frontend/src/components/BreadCrumbs.tsx (1)

9-16: Consider interface naming consistency.

The interface BCrumbItem could be renamed to BreadcrumbItem for consistency with the PageLayout component and better readability.

-interface BCrumbItem {
+interface BreadcrumbItem {
   title: string
   href: string
 }

 interface BreadCrumbsProps {
-  bcItems: BCrumbItem[]
+  bcItems: BreadcrumbItem[]
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b4cb61 and 677aea3.

📒 Files selected for processing (25)
  • frontend/__tests__/unit/components/BreadCrumbs.test.tsx (3 hunks)
  • frontend/__tests__/unit/pages/CommitteeDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/OrganizationDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/RepositoryDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/SnapshotDetails.test.tsx (2 hunks)
  • frontend/__tests__/unit/pages/UserDetails.test.tsx (3 hunks)
  • frontend/src/app/about/page.tsx (2 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (2 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/contribute/page.tsx (2 hunks)
  • frontend/src/app/layout.tsx (0 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
  • frontend/src/app/members/page.tsx (2 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/projects/[projectKey]/page.tsx (2 hunks)
  • frontend/src/app/projects/page.tsx (2 hunks)
  • frontend/src/app/snapshots/[id]/page.tsx (2 hunks)
  • frontend/src/app/snapshots/page.tsx (2 hunks)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
  • frontend/src/components/PageLayout.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/app/layout.tsx
🧰 Additional context used
🧬 Code Graph Analysis (14)
frontend/src/app/organizations/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/committees/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/contribute/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/snapshots/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/types/snapshot.ts (1)
  • Snapshots (21-26)
frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/chapters/[chapterKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/members/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/types/user.ts (1)
  • user (3-18)
frontend/src/app/committees/[committeeKey]/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/app/about/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/utils/aboutData.ts (2)
  • aboutText (1-5)
  • technologies (7-76)
frontend/src/components/PageLayout.tsx (1)
frontend/src/components/BreadCrumbs.tsx (1)
  • BreadCrumbs (18-68)
frontend/src/app/projects/[projectKey]/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
backend/apps/github/models/repository.py (1)
  • project (158-160)
frontend/src/app/snapshots/[id]/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
frontend/src/utils/dateFormatter.ts (1)
  • formatDate (1-20)
frontend/src/components/BreadCrumbs.tsx (1)
frontend/src/types/link.ts (1)
  • Link (1-6)
frontend/src/app/chapters/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (8-21)
🪛 Biome (1.9.4)
frontend/src/app/organizations/page.tsx

[error] 68-68: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/committees/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/contribute/page.tsx

[error] 86-86: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/members/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/projects/page.tsx

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/chapters/page.tsx

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (41)
frontend/__tests__/unit/pages/RepositoryDetails.test.tsx (1)

71-72: Excellent improvement to test accessibility and specificity.

The change from screen.getByText() to screen.getByRole('heading', { name: '...' }) is a great improvement that:

  • Makes the test more semantically specific by targeting heading elements
  • Follows accessibility testing best practices
  • Reduces the risk of false positives from other elements containing the same text
  • Aligns well with the PageLayout component refactoring
frontend/__tests__/unit/pages/CommitteeDetails.test.tsx (1)

54-55: Consistent improvement in test query specificity.

The update to use getByRole('heading', { name: '...' }) maintains consistency with the other test file improvements and enhances the test's semantic accuracy by specifically targeting heading elements.

frontend/__tests__/unit/pages/OrganizationDetails.test.tsx (1)

73-74: Good consistency in test query improvements.

The change to use role-based heading queries maintains the consistent pattern across the test suite and improves the semantic specificity of the test assertions.

frontend/__tests__/unit/pages/UserDetails.test.tsx (3)

91-92: Excellent test improvement for accessibility and specificity.

The change to use getByRole('heading', { name: 'Test User' }) improves the test by specifically targeting heading elements, following accessibility testing best practices and reducing false positive risks.


271-272: Consistent application of improved test queries.

Good continuation of the heading-specific query pattern in the user summary section test.


331-332: Thorough application of test improvements.

The consistent use of role-based queries throughout this test file demonstrates thorough attention to improving test specificity and accessibility practices.

frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1)

71-72: Excellent accessibility improvement in test assertion!

The change from text-based query to role-based query for the heading is a great improvement. Using getByRole('heading', { name: 'Test Project' }) is more semantically accurate and follows accessibility testing best practices.

frontend/__tests__/unit/pages/SnapshotDetails.test.tsx (1)

74-75: Consistent accessibility improvements across test cases!

Both test assertions have been properly updated to use role-based queries for headings. This maintains consistency with the accessibility testing improvements made across other page test files.

Also applies to: 149-150

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

8-8: Great implementation of the PageLayout wrapper pattern!

The integration of PageLayout follows the consistent pattern established across the codebase. The breadcrumb configuration is appropriate for the committees page, and all existing SearchPageLayout functionality is preserved.

Also applies to: 55-69

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

12-12: Excellent consistency with the PageLayout integration pattern!

The implementation perfectly follows the established pattern from other pages in this refactor. The breadcrumb configuration is appropriate and the existing SearchPageLayout functionality is fully preserved.

Also applies to: 74-88

frontend/src/app/members/[memberKey]/page.tsx (1)

26-26: LGTM! Clean breadcrumb navigation implementation.

The PageLayout integration is well-implemented with proper breadcrumb hierarchy (Members > Current Member). The fallback from user?.name to user?.login provides good user experience when the user's display name isn't available.

Also applies to: 195-216

frontend/src/app/chapters/[chapterKey]/page.tsx (1)

13-13: LGTM! Consistent breadcrumb implementation.

The PageLayout integration follows the established pattern with appropriate breadcrumb hierarchy (Chapters > Current Chapter). The chapter data is properly validated before rendering due to the existing error handling.

Also applies to: 64-81

frontend/src/app/projects/[projectKey]/page.tsx (1)

21-21: LGTM! Follows established breadcrumb pattern.

The PageLayout integration maintains consistency with other detail pages, using appropriate breadcrumb hierarchy (Projects > Current Project). The project data validation through existing error handling ensures breadcrumbs render safely.

Also applies to: 93-116

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

6-6: LGTM! Appropriate breadcrumb for search page.

The PageLayout integration is correctly implemented for a search page, with a single breadcrumb item for "Organizations" which is appropriate for a listing page.

Also applies to: 55-72

frontend/src/app/committees/[committeeKey]/page.tsx (2)

20-20: LGTM: Clean import addition.

The PageLayout import is correctly added to support the breadcrumb refactoring.


83-98: LGTM: Proper breadcrumb implementation.

The PageLayout integration is well-implemented with a logical breadcrumb hierarchy:

  • "Committees" → "/committees" (parent listing)
  • Committee name → current page

The DetailsCard props remain unchanged and are correctly nested within the PageLayout.

frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx (2)

20-20: LGTM: Appropriate import for breadcrumb refactoring.

The PageLayout import is correctly added to support the new breadcrumb navigation pattern.


110-135: LGTM: Well-structured breadcrumb hierarchy.

The PageLayout implementation provides a clear navigation path:

  • "Organizations" → "/organizations"
  • Organization name → "/organizations/{key}"
  • "Repositories" → "/organizations/{key}/repositories"
  • Repository name → current page

This creates an intuitive breadcrumb trail for users navigating deep into the organizational structure. The DetailsCard integration is seamless.

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

6-6: LGTM: Correct import for breadcrumb integration.

The PageLayout import is properly added to support the new breadcrumb navigation structure.


54-70: LGTM: Appropriate breadcrumb for top-level page.

The PageLayout integration with a single "Members" breadcrumb item is appropriate for this top-level listing page. The SearchPageLayout wrapping preserves all existing functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

10-10: LGTM: Proper import for breadcrumb functionality.

The PageLayout import is correctly added to support the breadcrumb navigation refactoring.


62-85: LGTM: Clean integration with preserved functionality.

The PageLayout wrapper with a single "Projects" breadcrumb item is appropriate for this top-level listing page. All SearchPageLayout props are correctly preserved, including the sortChildren configuration.

🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/organizations/[organizationKey]/page.tsx (2)

18-18: LGTM: Import statement is correct.

The PageLayout import is properly added and aligns with the new breadcrumb navigation pattern.


117-136: LGTM: PageLayout implementation is well-structured.

The breadcrumb navigation correctly shows the hierarchy from "Organizations" to the specific organization. The usage of organization.name for the title and organizationKey for the href provides appropriate context and navigation.

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

10-10: LGTM: Import statement is correct.

The PageLayout import follows the established pattern for breadcrumb navigation enhancement.


66-80: LGTM: PageLayout integration is clean and consistent.

The implementation correctly wraps the page content with appropriate breadcrumb navigation. The single breadcrumb item for "Snapshots" is suitable for this top-level page.

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

31-31: LGTM: Import statement is correct.

The PageLayout import is properly placed and consistent with the breadcrumb navigation enhancement.


102-240: LGTM: PageLayout integration maintains existing functionality.

The implementation correctly wraps all page content with appropriate breadcrumb navigation. The single breadcrumb item for "About" provides clear page context while preserving all existing UI components and interactions.

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

12-12: LGTM: Import statement is correct.

The PageLayout import follows the established pattern for breadcrumb navigation enhancement.


80-107: LGTM: PageLayout integration is well-implemented.

The PageLayout correctly wraps the SearchPageLayout with appropriate breadcrumb navigation for the Chapters page. The nested structure preserves all existing search functionality while adding consistent navigation.

🧰 Tools
🪛 Biome (1.9.4)

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

8-21: LGTM! Clean and well-structured component.

The PageLayout component follows React best practices with:

  • Clear TypeScript typing
  • Simple, focused responsibility
  • Proper component composition
  • Semantic HTML structure with the <main> element
frontend/src/app/snapshots/[id]/page.tsx (3)

19-19: LGTM! Proper import of the new PageLayout component.


113-118: Excellent implementation of breadcrumb navigation.

The breadcrumb implementation is well-structured with:

  • Appropriate hierarchy: Snapshots → Current Snapshot
  • Defensive programming with fallback title (snapshot?.title || 'Snapshot Details')
  • Correct URL paths matching the navigation structure

119-201: LGTM! Content properly wrapped in PageLayout.

The existing page content is correctly wrapped in the PageLayout component while preserving all functionality. The indentation changes are appropriate for the new structure.

frontend/__tests__/unit/components/BreadCrumbs.test.tsx (4)

5-9: Improved test approach - explicit props over mocked navigation.

The change from testing pathname-based behavior to explicit prop-based behavior makes the tests clearer and more maintainable. Testing with an empty array is more direct than mocking pathname.


11-26: LGTM! Comprehensive test with explicit breadcrumb items.

The test properly verifies:

  • Multiple breadcrumb segments render correctly
  • Home link is always present
  • All provided breadcrumb items are displayed

38-41: Correct assertion for non-clickable last segment.

The change from checking href attribute absence to verifying the element is not wrapped in an anchor tag is more accurate for the actual DOM structure.


43-78: Comprehensive test coverage maintained.

All important functionality is properly tested:

  • Correct href attributes on links
  • Hover styles applied to clickable elements
  • Last segment behavior (non-clickable)
frontend/src/components/BreadCrumbs.tsx (3)

6-6: LGTM! Appropriate use of lodash for empty array checking.


18-19: Excellent refactoring - simplified component responsibility.

The component now has a single, clear responsibility: rendering breadcrumbs from provided data. The early return for empty arrays is appropriate and prevents unnecessary DOM rendering.


45-63: LGTM! Clean implementation using provided breadcrumb items.

The refactored rendering logic:

  • Correctly iterates over provided bcItems
  • Uses item.href as key (unique identifier)
  • Properly handles last item as non-clickable
  • Uses item.title and item.href directly from props

This is much cleaner than the previous pathname parsing approach.

@codic-yeeshu
Copy link
Contributor Author

Hey @arkid15r ! I've looked at the nitpick comments by the code bot, and I don't think those changes should be considered for this PR. However, if changes are required, please let me know.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Works good! 👍🏼
Left some requests for naming, styling - and just general improvements.

type="chapter"
/>
<PageLayout
bcItems={[
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here - can we update this for a clearer naming? If it's conflicting with anything we can do something like crumbItem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated


interface BreadcrumbItem {
title: string
href: string
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think path is more suitable here than href

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

/>
<PageLayout
bcItems={[
{ title: 'Organizations', href: '/organizations' },
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we utilize usePathname from next/navigation to dynamically get the path, UpperCase it and use here for title and a path itself for href(should be named path)? Instead of hardcoding this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

@codic-yeeshu
Copy link
Contributor Author

Thank you for the feedback, @kasya . I’ll make the updates asap!.

@arkid15r arkid15r mentioned this pull request Jun 7, 2025
2 tasks
@github-actions github-actions bot added backend docker Pull requests that update Docker code ci schema labels Jun 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
frontend/src/app/committees/page.tsx (1)

67-67: Use optional chaining for safer array access.

The static analysis suggestion is valid. Consider using optional chaining to simplify the conditional rendering.

-        {committees && committees.map(renderCommitteeCard)}
+        {committees?.map(renderCommitteeCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

68-68: Simplify with optional chaining.

Apply the static analysis suggestion to use optional chaining for cleaner code.

-          {organizations && organizations.map(renderOrganizationCard)}
+          {organizations?.map(renderOrganizationCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 68-68: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

86-86: Apply optional chaining as suggested by static analysis.

The conditional rendering can be simplified using optional chaining.

-        {issues && issues.map(renderContributeCard)}
+        {issues?.map(renderContributeCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

83-83: Optimize chained operations with optional chaining.

The static analysis suggestion applies here as well, even with the filter chain.

-        {projects && projects.filter((project) => project.is_active).map(renderProjectCard)}
+        {projects?.filter((project) => project.is_active).map(renderProjectCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

67-67: Consider using optional chaining for cleaner code.

The static analysis tool correctly suggests using optional chaining instead of logical AND.

-          {users && users.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
+          {users?.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

105-105: Consider using optional chaining for cleaner code.

Similar to the members page, the static analysis tool correctly suggests using optional chaining instead of logical AND.

-        {chapters && chapters.filter((chapter) => chapter.is_active).map(renderChapterCard)}
+        {chapters?.filter((chapter) => chapter.is_active).map(renderChapterCard)}
🧰 Tools
🪛 Biome (1.9.4)

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fdc64a and e7ef862.

⛔ Files ignored due to path filters (4)
  • backend/poetry.lock is excluded by !**/*.lock
  • docs/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • schema/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • .github/workflows/run-ci-cd.yaml (6 hunks)
  • .github/workflows/run-code-ql.yaml (2 hunks)
  • .github/workflows/test-schema.yaml (1 hunks)
  • backend/docker/Dockerfile (2 hunks)
  • backend/docker/Dockerfile.local (2 hunks)
  • backend/docker/Dockerfile.test (2 hunks)
  • docs/docker/Dockerfile.local (2 hunks)
  • frontend/__tests__/unit/components/BreadCrumbs.test.tsx (3 hunks)
  • frontend/package.json (5 hunks)
  • frontend/src/app/about/page.tsx (2 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (2 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/contribute/page.tsx (2 hunks)
  • frontend/src/app/layout.tsx (1 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
  • frontend/src/app/members/page.tsx (2 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/projects/[projectKey]/page.tsx (2 hunks)
  • frontend/src/app/projects/page.tsx (2 hunks)
  • frontend/src/app/snapshots/[id]/page.tsx (2 hunks)
  • frontend/src/app/snapshots/page.tsx (2 hunks)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
  • frontend/src/components/CardDetailsPage.tsx (1 hunks)
  • frontend/src/components/PageLayout.tsx (1 hunks)
  • proxy/staging.conf (1 hunks)
  • schema/docker/Dockerfile.test (2 hunks)
✅ Files skipped from review due to trivial changes (11)
  • docs/docker/Dockerfile.local
  • backend/docker/Dockerfile.local
  • schema/docker/Dockerfile.test
  • frontend/src/components/CardDetailsPage.tsx
  • backend/docker/Dockerfile.test
  • proxy/staging.conf
  • .github/workflows/test-schema.yaml
  • frontend/package.json
  • backend/docker/Dockerfile
  • .github/workflows/run-code-ql.yaml
  • .github/workflows/run-ci-cd.yaml
🚧 Files skipped from review as they are similar to previous changes (13)
  • frontend/src/app/organizations/[organizationKey]/page.tsx
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx
  • frontend/src/app/committees/[committeeKey]/page.tsx
  • frontend/src/app/about/page.tsx
  • frontend/src/app/snapshots/[id]/page.tsx
  • frontend/src/app/snapshots/page.tsx
  • frontend/src/app/members/[memberKey]/page.tsx
  • frontend/src/app/chapters/[chapterKey]/page.tsx
  • frontend/src/app/projects/[projectKey]/page.tsx
  • frontend/tests/unit/components/BreadCrumbs.test.tsx
  • frontend/src/app/layout.tsx
  • frontend/src/components/PageLayout.tsx
  • frontend/src/components/BreadCrumbs.tsx
🧰 Additional context used
🧬 Code Graph Analysis (6)
frontend/src/app/chapters/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/app/committees/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/app/contribute/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/app/members/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/types/user.ts (1)
  • user (3-18)
frontend/src/app/organizations/page.tsx (1)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/app/projects/page.tsx (2)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (26-42)
frontend/src/utils/sortingOptions.ts (1)
  • sortOptionsProject (1-8)
🪛 Biome (1.9.4)
frontend/src/app/chapters/page.tsx

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/committees/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/contribute/page.tsx

[error] 86-86: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/members/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/organizations/page.tsx

[error] 68-68: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/projects/page.tsx

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (8)
frontend/src/app/committees/page.tsx (1)

8-8: PageLayout integration looks good.

The addition of PageLayout wrapper correctly implements the new breadcrumb navigation pattern. The component will now automatically generate breadcrumbs based on the current pathname and provide consistent layout structure.

Also applies to: 55-69

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

6-6: Consistent PageLayout implementation.

The PageLayout wrapper is correctly implemented, following the same pattern as other pages. This provides unified breadcrumb navigation and layout structure.

Also applies to: 55-71

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

12-12: PageLayout wrapper properly integrated.

The implementation maintains all existing functionality while adding the new layout and breadcrumb structure. Modal handling and issue rendering remain unchanged.

Also applies to: 74-88

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

10-10: PageLayout integration preserves all existing functionality.

The wrapper correctly maintains the sorting capabilities, pagination, and active project filtering while adding consistent breadcrumb navigation.

Also applies to: 62-85

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

6-6: LGTM! Import addition is correct.

The PageLayout import follows the established pattern and correctly references the new component that handles breadcrumb navigation.


54-70: LGTM! Clean PageLayout wrapper implementation.

The SearchPageLayout is properly wrapped with PageLayout without modifying any existing props or logic. This successfully implements the breadcrumb improvements outlined in the PR objectives.

🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

12-12: LGTM! Consistent import addition.

The PageLayout import is correctly added and maintains consistency with the pattern established across other pages.


80-107: LGTM! Consistent PageLayout wrapper implementation.

The SearchPageLayout is properly wrapped with PageLayout, maintaining all existing functionality while adding breadcrumb navigation. The implementation is consistent with the pattern applied across other pages.

🧰 Tools
🪛 Biome (1.9.4)

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

@github-actions github-actions bot removed backend docker Pull requests that update Docker code ci schema labels Jun 7, 2025
@codic-yeeshu codic-yeeshu requested a review from kasya June 8, 2025 07:46
dependabot bot and others added 16 commits June 28, 2025 21:01
…P#1590)

Bumps python from 3.13.4-alpine to 3.13.5-alpine.

---
updated-dependencies:
- dependency-name: python
  dependency-version: 3.13.5-alpine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add test for user.py

Signed-off-by: bandhan-majumder <[email protected]>

* update logical statement

Signed-off-by: bandhan-majumder <[email protected]>

* add __init__.py

Signed-off-by: bandhan-majumder <[email protected]>

* Update code

---------

Signed-off-by: bandhan-majumder <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
* Add test for generate sitemap

Signed-off-by: bandhan-majumder <[email protected]>

* Update code

---------

Signed-off-by: bandhan-majumder <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
* rate limiting

* code rabbit suggestion
* Creating a command to update metrics - initial step

* Add missing properties to the project model and update the metrics script

* Apply make-check and check-spelling

* Update tests

* Apply coderabbitai suggestion

* Add is_funding_requirements_compliant to the metrics script

* Apply coderabbitai suggestion

* Add owasp_page_last_updated_at to the metrics

* Refactor is_funding_requirements_compliant logic

* Add command to calculate score

* Remove TODO

* Add metrics test

* Add metrics_score test

* Update metrics test

* Apply suggestions and add tests

* Rename score script to be plural

* Change the logic to create multiple ProjectHealthMetrics objects for a project and apply suggestions

* Apply coderabbitai suggestion

* Make open issues count negative direction

* Evaluate the funding and project leaders requirement in the score and add tests

* Apply suggestions

* Apply coderabbitai suggestion

* Apply coderabbitai suggetion

* Fix tests

* Update code

* Apply suggestions

* Fix if condition

* Update code

* Make older projects have higher scores

---------

Co-authored-by: Kate Golovanova <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
* Resolved bug: truncating repo name

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
* Resolved bug: Made header buttons consistent

* Update NavButton padding

* Update after make check

---------

Co-authored-by: Kate <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🔭 Outside diff range comments (1)
frontend/src/components/ContributorAvatar.tsx (1)

12-19: Type guard function has inconsistent property checks.

The isAlgoliaContributor function checks for snake_case properties (avatar_url, contributions_count) but the Contributor type uses camelCase properties (avatarUrl, contributionsCount). This type guard will always return false.

Fix the property names to match the Contributor type:

-const isAlgoliaContributor = (contributor: Contributor): contributor is Contributor => {
+const isAlgoliaContributor = (contributor: Contributor): boolean => {
   return (
     typeof contributor === 'object' &&
     contributor !== null &&
-    'avatar_url' in contributor &&
-    'contributions_count' in contributor
+    'avatarUrl' in contributor &&
+    'contributionsCount' in contributor
   )
 }

Or better yet, if you're unifying types, consider removing this type guard entirely and handle the data transformation at the data layer.

🧹 Nitpick comments (16)
.github/ansible/staging/nest.yaml (1)

114-123: Duplicate cron-installation logic – factor into a reusable role or include_tasks

The staging playbook repeats the same copy/crontab block introduced in production. This invites drift between environments and increases maintenance cost.

Consider extracting the cron-deployment into:

  • a dedicated role (roles/manage_crontab/tasks/main.yaml) parameterised by the environment name
  • or a single task file included with vars: overrides.

This eliminates duplication and ensures both environments follow the same hardening / idempotency improvements suggested for production.

backend/apps/core/utils/index.py (1)

166-183: Improve type annotations and handle edge cases.

The function logic is correct, but the implementation could be more robust:

  1. The return type annotation dict | list doesn't cover all possible return values (primitive types)
  2. Consider handling other iterable types like tuples and sets
  3. Add input validation for unexpected types

Apply this diff to improve the function:

-def deep_camelize(obj) -> dict | list:
+def deep_camelize(obj: any) -> any:
     """Deep camelize.
 
     Args:
-        obj: The object to camelize.
+        obj: The object to camelize (dict, list, or primitive).
 
     Returns:
-        The camelize object.
+        The camelized object with converted keys.
 
     """
     if isinstance(obj, dict):
         return {
             convert_to_camel_case(key.removeprefix("idx_")): deep_camelize(value)
             for key, value in obj.items()
         }
-    if isinstance(obj, list):
+    elif isinstance(obj, (list, tuple)):
+        result = [deep_camelize(item) for item in obj]
+        return tuple(result) if isinstance(obj, tuple) else result
+    elif isinstance(obj, set):
+        return {deep_camelize(item) for item in obj}
+    else:
-        return [deep_camelize(item) for item in obj]
-    return obj
+        return obj
frontend/src/app/committees/page.tsx (1)

67-67: Use optional chaining for safer array access.

The static analysis tool correctly identifies that committees could be undefined. Use optional chaining to prevent potential runtime errors.

Apply this diff:

-        {committees && committees.map(renderCommitteeCard)}
+        {committees?.map(renderCommitteeCard)}
frontend/src/app/members/page.tsx (1)

67-67: Use optional chaining for cleaner code.

The current conditional rendering can be simplified using optional chaining.

-        <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
-          {users && users.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
-        </div>
+        <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
+          {users?.map((user) => <div key={user.key}>{renderUserCard(user)}</div>)}
+        </div>
backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py (1)

63-63: Consider adding transaction management for data integrity.

The bulk save operation should be wrapped in a transaction to ensure data consistency.

+        from django.db import transaction
+        
+        with transaction.atomic():
             ProjectHealthMetrics.bulk_save(project_health_metrics, fields=["score"])
frontend/src/app/chapters/page.tsx (1)

105-105: Use optional chaining for safer array access.

The current condition can be simplified and made safer using optional chaining.

-        {chapters && chapters.filter((chapter) => chapter.isActive).map(renderChapterCard)}
+        {chapters?.filter((chapter) => chapter.isActive).map(renderChapterCard)}
frontend/src/app/organizations/page.tsx (1)

68-68: Use optional chaining for safer array access.

-          {organizations && organizations.map(renderOrganizationCard)}
+          {organizations?.map(renderOrganizationCard)}
frontend/src/app/projects/page.tsx (1)

83-83: Use optional chaining for safer array access.

-        {projects && projects.filter((project) => project.isActive).map(renderProjectCard)}
+        {projects?.filter((project) => project.isActive).map(renderProjectCard)}
frontend/src/app/contribute/page.tsx (1)

86-86: Use optional chaining for safer array access.

-        {issues && issues.map(renderContributeCard)}
+        {issues?.map(renderContributeCard)}
backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (2)

11-11: Consider making the expected score calculation more explicit.

The hard-coded EXPECTED_SCORE = 52.0 makes the test brittle and doesn't clearly show how this value is derived from the test data.

Consider calculating the expected score based on the test data to make the test more maintainable:

-EXPECTED_SCORE = 52.0
+# Calculate expected score based on test weights
+# With all fields having weights (5, 6), the calculation would be:
+# score = (sum of metric_weights / sum of requirement_weights) * 100
+# score = (15 * 5) / (15 * 6) * 100 = 75/90 * 100 ≈ 83.33
+# But the actual algorithm may be different - verify against implementation
+EXPECTED_SCORE = 52.0  # TODO: Calculate this based on the algorithm

36-79: Comprehensive test coverage with room for edge case testing.

The test method covers the main success path well, but consider adding tests for edge cases such as:

  • Projects with missing requirements
  • Projects with null metric values
  • Division by zero scenarios

The test data setup is thorough, but you might want to extract the field weights setup into a separate fixture or helper method to improve readability and reusability.

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_test.py (3)

6-6: Unused import detected.

The ModelState import from django.db.models.base appears to be used only on line 54, but it's questionable whether this is necessary for the test.

Consider removing this import if the ModelState() assignment on line 54 is not actually required for the test to function properly.


31-62: Consider extracting test data setup into a helper method.

The test data dictionary is quite large and makes the test method less readable. Consider extracting this into a fixture or helper method.

+@pytest.fixture
+def sample_project_data():
+    """Sample project data for testing."""
+    return {
+        "name": "Test Project",
+        "contributors_count": 10,
+        # ... rest of the data
+    }

-def test_handle_successful_update(self):
+def test_handle_successful_update(self, sample_project_data):
     """Test successful metrics update."""
-    test_data = {
-        "name": "Test Project",
-        # ... large dictionary
-    }
+    test_data = sample_project_data

54-54: Verify necessity of ModelState assignment.

The ModelState() assignment may be unnecessary for this test. Django's MagicMock should handle model instances without explicit state management in most test scenarios.

Consider removing this line if the test passes without it:

-mock_project._state = ModelState()
backend/tests/apps/common/management/commands/generate_sitemap_test.py (1)

120-122: Reduce method parameter count.

The method has too many parameters (7), which makes it hard to read and maintain.

Consider grouping related mocks or using a fixture to set up the mocks:

+@pytest.fixture
+def sitemap_mocks(self):
+    """Set up all sitemap generation mocks."""
+    with (
+        patch("apps.common.management.commands.generate_sitemap.Command.generate_chapter_sitemap") as mock_chapter,
+        patch("apps.common.management.commands.generate_sitemap.Command.generate_committee_sitemap") as mock_committee,
+        # ... other patches
+    ):
+        yield {
+            'chapter': mock_chapter,
+            'committee': mock_committee,
+            # ... other mocks
+        }

-def test_handle_success(
-    self, mock_save, mock_index, mock_user, mock_project, mock_committee, mock_chapter
-):
+def test_handle_success(self, sitemap_mocks):
frontend/src/components/ChapterMap.tsx (1)

51-51: Consider performance impact of removing useMemo.

While the direct usage of geoLocData simplifies the code, removing the useMemo hook means marker creation will happen on every render. If geoLocData is stable across renders, this should be fine, but monitor for performance issues with large datasets.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b510369 and f27b4f5.

⛔ Files ignored due to path filters (4)
  • backend/poetry.lock is excluded by !**/*.lock
  • cspell/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • docs/poetry.lock is excluded by !**/*.lock
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (107)
  • .github/ansible/production/nest.yaml (1 hunks)
  • .github/ansible/staging/nest.yaml (1 hunks)
  • .github/workflows/run-ci-cd.yaml (2 hunks)
  • .github/workflows/run-code-ql.yaml (2 hunks)
  • .github/workflows/test-schema.yaml (1 hunks)
  • Makefile (1 hunks)
  • backend/Makefile (1 hunks)
  • backend/apps/common/utils.py (1 hunks)
  • backend/apps/core/api/algolia.py (4 hunks)
  • backend/apps/core/utils/index.py (2 hunks)
  • backend/apps/owasp/admin.py (2 hunks)
  • backend/apps/owasp/management/commands/owasp_update_project_health_metrics.py (1 hunks)
  • backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py (1 hunks)
  • backend/apps/owasp/management/commands/owasp_update_project_health_requirements.py (5 hunks)
  • backend/apps/owasp/migrations/0035_rename_total_pull_request_count_projecthealthmetrics_total_pull_requests_count.py (1 hunks)
  • backend/apps/owasp/migrations/0036_alter_projecthealthmetrics_score.py (1 hunks)
  • backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py (1 hunks)
  • backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (1 hunks)
  • backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (1 hunks)
  • backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (1 hunks)
  • backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (1 hunks)
  • backend/apps/owasp/migrations/0042_alter_projecthealthmetrics_score.py (1 hunks)
  • backend/apps/owasp/models/project.py (7 hunks)
  • backend/apps/owasp/models/project_health_metrics.py (4 hunks)
  • backend/apps/owasp/models/project_health_requirements.py (1 hunks)
  • backend/apps/owasp/scraper.py (3 hunks)
  • backend/apps/slack/management/commands/slack_sync_messages.py (12 hunks)
  • backend/docker/Dockerfile (2 hunks)
  • backend/docker/Dockerfile.local (2 hunks)
  • backend/docker/Dockerfile.test (2 hunks)
  • backend/pyproject.toml (1 hunks)
  • backend/tests/apps/common/management/commands/generate_sitemap_test.py (1 hunks)
  • backend/tests/apps/common/utils_test.py (2 hunks)
  • backend/tests/apps/core/api/algolia_test.py (4 hunks)
  • backend/tests/apps/core/api/csrf_test.py (2 hunks)
  • backend/tests/apps/github/api/search/user_test.py (1 hunks)
  • backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (1 hunks)
  • backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_test.py (1 hunks)
  • backend/tests/apps/owasp/management/commands/owasp_update_project_health_requirements_test.py (1 hunks)
  • backend/tests/apps/owasp/models/project_health_metrics_test.py (3 hunks)
  • backend/tests/apps/owasp/scraper_test.py (8 hunks)
  • backend/tests/slack/commands/management/slack_sync_messages_test.py (14 hunks)
  • cron/production (1 hunks)
  • cron/staging (1 hunks)
  • cspell/custom-dict.txt (1 hunks)
  • docs/docker/Dockerfile.local (2 hunks)
  • frontend/__tests__/unit/data/mockChapterData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockCommitteeData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockContributeData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockHomeData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockOrganizationData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockProjectData.ts (2 hunks)
  • frontend/__tests__/unit/data/mockUserData.ts (1 hunks)
  • frontend/package.json (4 hunks)
  • frontend/src/app/about/page.tsx (3 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (2 hunks)
  • frontend/src/app/chapters/page.tsx (5 hunks)
  • frontend/src/app/committees/[committeeKey]/page.tsx (2 hunks)
  • frontend/src/app/committees/page.tsx (3 hunks)
  • frontend/src/app/contribute/page.tsx (4 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
  • frontend/src/app/members/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 (6 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (2 hunks)
  • frontend/src/app/projects/page.tsx (2 hunks)
  • frontend/src/app/snapshots/[id]/page.tsx (4 hunks)
  • frontend/src/app/snapshots/page.tsx (3 hunks)
  • frontend/src/components/BreadCrumbs.tsx (2 hunks)
  • frontend/src/components/Card.tsx (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (5 hunks)
  • frontend/src/components/ChapterMap.tsx (5 hunks)
  • frontend/src/components/ChapterMapWrapper.tsx (1 hunks)
  • frontend/src/components/ContributorAvatar.tsx (2 hunks)
  • frontend/src/components/DisplayIcon.tsx (1 hunks)
  • frontend/src/components/Footer.tsx (1 hunks)
  • frontend/src/components/Header.tsx (2 hunks)
  • frontend/src/components/InfoBlock.tsx (1 hunks)
  • frontend/src/components/ItemCardList.tsx (2 hunks)
  • frontend/src/components/LeadersList.tsx (1 hunks)
  • frontend/src/components/LogoCarousel.tsx (1 hunks)
  • frontend/src/components/Milestones.tsx (2 hunks)
  • frontend/src/components/Modal.tsx (1 hunks)
  • frontend/src/components/MultiSearch.tsx (6 hunks)
  • frontend/src/components/NavButton.tsx (2 hunks)
  • frontend/src/components/NavDropDown.tsx (1 hunks)
  • frontend/src/components/PageLayout.tsx (1 hunks)
  • frontend/src/components/RecentIssues.tsx (1 hunks)
  • frontend/src/components/RecentPullRequests.tsx (1 hunks)
  • frontend/src/components/RecentReleases.tsx (1 hunks)
  • frontend/src/components/RepositoriesCard.tsx (1 hunks)
  • frontend/src/components/SnapshotCard.tsx (1 hunks)
  • frontend/src/components/SortBy.tsx (1 hunks)
  • frontend/src/components/TopContributorsList.tsx (2 hunks)
  • frontend/src/components/UserCard.tsx (3 hunks)
  • frontend/src/components/skeletons/Card.tsx (1 hunks)
  • frontend/src/components/skeletons/UserCard.tsx (1 hunks)
  • frontend/src/server/fetchAlgoliaData.ts (3 hunks)
  • frontend/src/server/utility.ts (0 hunks)
  • frontend/src/types/algolia.ts (1 hunks)
  • frontend/src/types/button.ts (1 hunks)
  • frontend/src/types/card.ts (3 hunks)
  • frontend/src/types/chapter.ts (1 hunks)
  • frontend/src/types/committee.ts (1 hunks)
  • frontend/src/types/contributor.ts (1 hunks)
  • frontend/src/types/event.ts (1 hunks)
⛔ Files not processed due to max files limit (22)
  • frontend/src/types/home.ts
  • frontend/src/types/icon.ts
  • frontend/src/types/issue.ts
  • frontend/src/types/leaders.ts
  • frontend/src/types/level.ts
  • frontend/src/types/link.ts
  • frontend/src/types/milestone.ts
  • frontend/src/types/modal.ts
  • frontend/src/types/organization.ts
  • frontend/src/types/project.ts
  • frontend/src/types/pullRequest.ts
  • frontend/src/types/release.ts
  • frontend/src/types/search.ts
  • frontend/src/types/section.ts
  • frontend/src/types/skeleton.ts
  • frontend/src/types/snapshot.ts
  • frontend/src/types/sortBy.ts
  • frontend/src/types/user.ts
  • frontend/src/utils/constants.ts
  • frontend/src/utils/logger.ts
  • frontend/src/utils/utility.ts
  • schema/docker/Dockerfile.test
💤 Files with no reviewable changes (1)
  • frontend/src/server/utility.ts
✅ Files skipped from review due to trivial changes (46)
  • backend/docker/Dockerfile
  • backend/docker/Dockerfile.local
  • cron/staging
  • frontend/src/components/skeletons/Card.tsx
  • docs/docker/Dockerfile.local
  • frontend/src/components/Modal.tsx
  • backend/docker/Dockerfile.test
  • frontend/src/components/skeletons/UserCard.tsx
  • frontend/src/components/SnapshotCard.tsx
  • frontend/src/components/InfoBlock.tsx
  • cspell/custom-dict.txt
  • cron/production
  • frontend/src/components/Card.tsx
  • frontend/tests/unit/data/mockUserData.ts
  • frontend/src/types/event.ts
  • frontend/src/components/DisplayIcon.tsx
  • .github/workflows/run-code-ql.yaml
  • backend/pyproject.toml
  • backend/tests/apps/core/api/csrf_test.py
  • frontend/src/components/UserCard.tsx
  • frontend/src/components/NavButton.tsx
  • frontend/tests/unit/data/mockCommitteeData.ts
  • frontend/src/components/LogoCarousel.tsx
  • frontend/tests/unit/data/mockContributeData.ts
  • backend/apps/owasp/scraper.py
  • .github/workflows/test-schema.yaml
  • .github/workflows/run-ci-cd.yaml
  • frontend/tests/unit/data/mockChapterData.ts
  • frontend/tests/unit/data/mockProjectData.ts
  • frontend/src/components/RecentReleases.tsx
  • frontend/src/components/TopContributorsList.tsx
  • frontend/src/components/ChapterMapWrapper.tsx
  • frontend/src/types/algolia.ts
  • backend/tests/apps/core/api/algolia_test.py
  • frontend/tests/unit/data/mockHomeData.ts
  • backend/Makefile
  • frontend/src/types/chapter.ts
  • frontend/src/components/ItemCardList.tsx
  • frontend/src/components/Footer.tsx
  • frontend/src/app/page.tsx
  • frontend/src/components/MultiSearch.tsx
  • frontend/package.json
  • frontend/src/components/Milestones.tsx
  • frontend/src/components/Header.tsx
  • frontend/src/components/SortBy.tsx
  • frontend/src/types/card.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • frontend/src/app/members/[memberKey]/page.tsx
  • frontend/src/app/snapshots/page.tsx
  • frontend/src/app/projects/[projectKey]/page.tsx
  • frontend/src/app/snapshots/[id]/page.tsx
  • frontend/src/app/committees/[committeeKey]/page.tsx
  • frontend/src/components/CardDetailsPage.tsx
  • frontend/src/app/organizations/[organizationKey]/repositories/[repositoryKey]/page.tsx
  • frontend/src/app/chapters/[chapterKey]/page.tsx
  • frontend/src/app/about/page.tsx
  • frontend/src/components/BreadCrumbs.tsx
🧰 Additional context used
🧠 Learnings (2)
frontend/src/components/NavDropDown.tsx (1)
Learnt from: codic-yeeshu
PR: OWASP/Nest#1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: Use React's useId() hook rather than manually generating random strings when creating accessibility identifiers for UI components. This creates stable, unique IDs without causing hydration mismatches.
backend/tests/apps/owasp/models/project_health_metrics_test.py (1)
Learnt from: ahmedxgouda
PR: OWASP/Nest#1633
File: frontend/src/components/GradientRadialChart.tsx:113-113
Timestamp: 2025-06-21T12:22:01.889Z
Learning: In the OWASP Nest project, health metrics requirements (like lastCommitDaysRequirement, lastReleaseDaysRequirement) should never be 0. A requirement value of 0 is considered invalid and should result in displaying 0 on the radial chart.
🧬 Code Graph Analysis (25)
frontend/src/server/fetchAlgoliaData.ts (1)
frontend/src/types/algolia.ts (1)
  • AlgoliaResponse (1-4)
backend/apps/core/api/algolia.py (1)
backend/apps/core/utils/index.py (2)
  • deep_camelize (166-183)
  • get_params_for_index (12-137)
backend/tests/apps/github/api/search/user_test.py (1)
backend/apps/github/api/search/user.py (1)
  • get_users (10-61)
backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (3)
backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (1)
  • Migration (6-23)
backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-20)
backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-22)
backend/tests/apps/common/utils_test.py (1)
backend/apps/common/utils.py (1)
  • convert_to_camel_case (15-32)
backend/apps/owasp/models/project_health_requirements.py (1)
backend/apps/owasp/models/project.py (2)
  • is_funding_requirements_compliant (146-148)
  • is_leader_requirements_compliant (151-155)
backend/apps/core/utils/index.py (1)
backend/apps/common/utils.py (1)
  • convert_to_camel_case (15-32)
backend/apps/owasp/migrations/0036_alter_projecthealthmetrics_score.py (3)
backend/apps/owasp/migrations/0035_rename_total_pull_request_count_projecthealthmetrics_total_pull_requests_count.py (1)
  • Migration (6-17)
backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py (1)
  • Migration (7-22)
backend/apps/owasp/migrations/0042_alter_projecthealthmetrics_score.py (1)
  • Migration (7-27)
frontend/src/components/RecentIssues.tsx (1)
frontend/src/types/issue.ts (1)
  • Issue (3-19)
frontend/src/components/RecentPullRequests.tsx (1)
frontend/src/types/pullRequest.ts (1)
  • PullRequest (3-10)
backend/apps/owasp/management/commands/owasp_update_project_health_metrics.py (2)
backend/apps/owasp/models/project.py (2)
  • Project (24-367)
  • bulk_save (334-342)
backend/apps/owasp/models/project_health_metrics.py (2)
  • ProjectHealthMetrics (10-113)
  • bulk_save (105-113)
backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (4)
backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py (1)
  • Migration (7-22)
backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-20)
backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (1)
  • Migration (6-26)
backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-22)
backend/tests/apps/common/management/commands/generate_sitemap_test.py (1)
backend/apps/common/management/commands/generate_sitemap.py (11)
  • generate_project_sitemap (73-92)
  • generate_chapter_sitemap (94-113)
  • generate_committee_sitemap (115-137)
  • generate_user_sitemap (139-162)
  • create_url_entry (207-224)
  • create_sitemap_index_entry (226-238)
  • create_sitemap (240-255)
  • create_sitemap_index (257-272)
  • save_sitemap (275-284)
  • generate_sitemap_content (164-186)
  • generate_index_sitemap (188-205)
backend/apps/owasp/admin.py (1)
backend/apps/owasp/models/project_health_metrics.py (1)
  • ProjectHealthMetrics (10-113)
frontend/src/components/ContributorAvatar.tsx (1)
frontend/src/types/contributor.ts (1)
  • Contributor (1-8)
backend/tests/slack/commands/management/slack_sync_messages_test.py (2)
backend/tests/slack/commands/management/slack_sync_data_test.py (1)
  • command (24-26)
backend/apps/slack/management/commands/slack_sync_messages.py (1)
  • handle (44-80)
frontend/src/types/committee.ts (1)
frontend/src/types/contributor.ts (1)
  • Contributor (1-8)
backend/apps/owasp/models/project_health_metrics.py (3)
backend/apps/common/models.py (2)
  • BulkSaveModel (8-30)
  • TimestampedModel (33-40)
backend/apps/owasp/models/project.py (5)
  • Meta (35-40)
  • is_leader_requirements_compliant (151-155)
  • pull_request_last_created_at (225-229)
  • owasp_page_last_updated_at (206-208)
  • bulk_save (334-342)
backend/apps/owasp/admin.py (1)
  • project (186-188)
frontend/src/components/PageLayout.tsx (1)
frontend/src/components/BreadCrumbs.tsx (2)
  • BreadCrumbItem (9-12)
  • BreadCrumbs (18-68)
backend/apps/owasp/models/project.py (2)
backend/apps/owasp/graphql/nodes/project.py (3)
  • repositories (75-77)
  • issues_count (38-40)
  • repositories_count (80-82)
backend/apps/github/models/repository.py (1)
  • published_releases (163-169)
backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py (2)
backend/apps/owasp/migrations/0036_alter_projecthealthmetrics_score.py (1)
  • Migration (7-28)
backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (1)
  • Migration (6-23)
backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (3)
backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (1)
  • Migration (6-23)
backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (1)
  • Migration (6-26)
backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-22)
backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (3)
backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py (1)
  • Migration (6-23)
backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (1)
  • Migration (6-20)
backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (1)
  • Migration (6-26)
frontend/src/app/chapters/page.tsx (6)
frontend/src/types/chapter.ts (1)
  • Chapter (3-19)
frontend/src/hooks/useSearchPage.ts (1)
  • useSearchPage (29-139)
frontend/src/types/algolia.ts (1)
  • AlgoliaResponse (1-4)
frontend/src/server/fetchAlgoliaData.ts (1)
  • fetchAlgoliaData (6-59)
frontend/src/utils/utility.ts (2)
  • getFilteredIcons (22-35)
  • handleSocialUrls (37-45)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (41-60)
frontend/src/app/contribute/page.tsx (3)
frontend/src/hooks/useSearchPage.ts (1)
  • useSearchPage (29-139)
frontend/src/types/issue.ts (1)
  • Issue (3-19)
frontend/src/components/PageLayout.tsx (1)
  • PageLayout (41-60)
🪛 Flake8 (7.2.0)
backend/apps/common/utils.py

[error] 27-27: whitespace before ':'

(E203)


[error] 30-30: whitespace before ':'

(E203)

🪛 Pylint (3.3.7)
backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py

[refactor] 9-9: Too few public methods (1/2)

(R0903)

backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0036_alter_projecthealthmetrics_score.py

[refactor] 7-7: Too few public methods (0/2)

(R0903)

backend/apps/owasp/management/commands/owasp_update_project_health_metrics.py

[refactor] 9-9: Too few public methods (1/2)

(R0903)

backend/apps/owasp/migrations/0038_remove_projecthealthmetrics_is_project_leaders_requirements_compliant_and_more.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_test.py

[refactor] 13-13: Too few public methods (1/2)

(R0903)

backend/apps/owasp/migrations/0042_alter_projecthealthmetrics_score.py

[refactor] 7-7: Too few public methods (0/2)

(R0903)

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py

[refactor] 14-14: Too few public methods (1/2)

(R0903)

backend/tests/apps/common/management/commands/generate_sitemap_test.py

[refactor] 18-18: Consider using 'with' for resource-allocating operations

(R1732)


[refactor] 120-120: Too many arguments (7/5)

(R0913)


[refactor] 120-120: Too many positional arguments (7/5)

(R0917)

backend/apps/owasp/admin.py

[refactor] 167-167: Too few public methods (1/2)

(R0903)

backend/apps/owasp/models/project_health_metrics.py

[refactor] 13-13: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0035_rename_total_pull_request_count_projecthealthmetrics_total_pull_requests_count.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py

[refactor] 7-7: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py

[refactor] 6-6: Too few public methods (0/2)

(R0903)

backend/tests/apps/owasp/scraper_test.py

[error] 123-123: Class 'HTTPStatus' has no 'IM_A_TEAPOT' member

(E1101)

🪛 Biome (1.9.4)
frontend/src/app/chapters/page.tsx

[error] 105-105: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/committees/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/contribute/page.tsx

[error] 86-86: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/members/page.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/organizations/page.tsx

[error] 68-68: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

frontend/src/app/projects/page.tsx

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (75)
frontend/src/components/RepositoriesCard.tsx (1)

13-13: LGTM! Excellent TypeScript best practice.

Converting to type-only imports is a great improvement that:

  • Makes the intent explicit (these are used only for type checking)
  • Can improve compilation efficiency
  • Helps prevent potential circular dependency issues
  • Aligns with the broader codebase refactoring pattern
frontend/src/components/NavDropDown.tsx (1)

5-5: LGTM! Good TypeScript best practice.

Converting to a type-only import is the correct approach since LinkType is only used for type annotations. This improves bundle optimization and clearly indicates the import's purpose.

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

5-5: Good use of type-only import syntax.

Using import type is a TypeScript best practice that improves bundle size and clearly indicates type-only usage.

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

5-5: Consistent use of type-only import syntax.

Good practice using import type for type-only imports, consistent with the broader codebase refactor.


5-5: Date format consistency confirmed – no changes needed.

The formatDate utility accepts both number and string inputs (Unix timestamps and ISO strings), so using PullRequest.createdAt: string alongside Issue.createdAt: number is safe. All type changes are sound and can be approved.

backend/tests/slack/commands/management/slack_sync_messages_test.py (7)

12-13: LGTM! Good use of constants.

Using a constant for the expected argument count improves maintainability.


159-159: Test updates correctly include the new max_retries parameter.

All handle() method calls have been consistently updated to include the new max_retries=5 parameter, matching the command's default value.

Also applies to: 173-173, 225-225


247-248: Consistent parameter updates for _create_message_from_data calls.

All test calls to _create_message_from_data have been properly updated to include the new delay and max_retries parameters. Using a smaller delay value (0.5) in tests is appropriate for faster execution.

Also applies to: 266-267, 285-286, 317-318, 346-347


292-294: Appropriate mocking of time.sleep for rate limit handling.

Good addition of time.sleep mocking to prevent actual delays during testing, especially important for this test case which exercises the member creation path that includes retry logic.


364-364: Docstring correction to match actual method name.

Good catch on updating the docstring to reflect the correct method name _fetch_replies.


389-389: Test correctly includes max_retries parameter for _fetch_replies.

The test has been properly updated to include the new max_retries parameter.


416-443: Test correctly validates all command arguments including the new max-retries.

The test properly:

  • Updates the expected argument count to 4
  • Reflects the new default delay value of 4 seconds
  • Adds assertion for the new --max-retries argument with correct defaults and help text
backend/apps/slack/management/commands/slack_sync_messages.py (6)

29-42: Well-structured command arguments for rate limit handling.

The changes appropriately:

  • Increase the default delay to 4 seconds to be more conservative with Slack's rate limits
  • Add a new --max-retries argument with a sensible default of 5 retries

48-48: Proper propagation of max_retries parameter throughout the command.

The max_retries parameter is correctly extracted from options and consistently passed to all methods that need it.

Also applies to: 76-76, 88-88, 111-111


113-113: Good addition of delay between reply fetches.

Adding a delay after fetching each message's replies helps prevent hitting rate limits when processing conversations with many threaded messages.


187-203: Well-implemented retry logic for rate limiting in message fetching.

The retry implementation correctly:

  • Detects rate limit errors and respects the Retry-After header
  • Falls back to exponential backoff when the header is not present
  • Logs informative messages about retry attempts
  • Properly breaks the loop when max retries are exceeded
  • Resets the retry counter after successful requests

278-299: Consistent retry logic implementation for fetching replies.

The retry logic for _fetch_replies follows the same pattern as _fetch_messages, ensuring consistent behavior across the command. The implementation properly handles rate limiting with appropriate retries and delays.


325-329: Consider if excluding bot_message subtype is within PR scope.

The addition of "bot_message" to excluded subtypes appears unrelated to the rate limiting improvements. If this is an intentional change, it should be documented in the PR description.

Verify if this change is intentional and document the reasoning for excluding bot messages from sync.

Makefile (1)

24-27: LGTM: Logical reordering of check targets.

Running spelling checks first makes sense as it's typically faster than backend/frontend checks and can catch simple issues early in the pipeline.

backend/apps/common/utils.py (1)

15-32: Well-implemented camelCase conversion function.

The function correctly handles various edge cases including leading underscores and preserves the first word's case while capitalizing subsequent words. The logic is sound and the implementation is clean.

Note: The static analysis hints about whitespace before ':' (E203) are false positives - this is valid Python slice notation style that's compatible with black formatter.

frontend/src/types/button.ts (1)

1-19: Excellent TypeScript modernization.

The changes demonstrate good TypeScript practices:

  • Using import type for type-only imports improves build performance
  • Renaming ButtonType to Button follows naming conventions
  • Converting to type aliases is appropriate for simple object types
  • Consistent camelCase property naming improves code consistency
frontend/src/components/LeadersList.tsx (1)

2-2: Consistent with TypeScript modernization effort.

Using import type for type-only imports is a good practice that improves build performance and makes the import intent clear.

backend/apps/owasp/migrations/0035_rename_total_pull_request_count_projecthealthmetrics_total_pull_requests_count.py (1)

1-17: Standard Django migration for field renaming.

The migration correctly renames the field to use plural form "pull_requests_count" which is more semantically accurate. The migration structure follows Django conventions properly.

Note: The Pylint warning about "too few public methods" is not relevant for Django migration classes, which are meant to be simple and focused on specific database changes.

backend/apps/owasp/migrations/0039_rename_is_leaders_requirements_compliant_projecthealthmetrics_is_leader_requirements_compliant.py (1)

15-19: LGTM! Grammatical correction in field naming.

The field rename from is_leaders_requirements_compliant to is_leader_requirements_compliant makes grammatical sense, using the singular form "leader" which is more appropriate for this context.

frontend/__tests__/unit/data/mockOrganizationData.ts (1)

5-32: LGTM! Consistent camelCase property naming.

The systematic renaming of properties from snake_case to camelCase (e.g., avatar_urlavatarUrl, collaborators_countcollaboratorsCount) aligns with JavaScript/TypeScript naming conventions and improves consistency across the frontend codebase.

backend/apps/core/api/algolia.py (4)

6-6: LGTM! Using standard library for HTTP status codes.

Importing HTTPStatus from the standard library instead of using the requests module is a good improvement for consistency and reduces dependencies.


17-17: LGTM! Adding deep camelization utility.

The import of deep_camelize supports the data transformation needed to standardize API responses for frontend consumption.


62-62: LGTM! Standardizing data format for frontend.

Applying deep_camelize to the search results ensures consistent camelCase naming and removes "idx_" prefixes, improving frontend data consistency.


80-80: LGTM! Consistent HTTP status usage.

Using HTTPStatus.METHOD_NOT_ALLOWED is consistent with the import change and follows standard library conventions.

frontend/src/server/fetchAlgoliaData.ts (3)

2-2: LGTM! Updated type import.

The change from AlgoliaResponseType to AlgoliaResponse aligns with the updated type definitions in the codebase.


12-12: LGTM! Simplified return type.

The updated return type Promise<AlgoliaResponse<T>> is consistent with the new type definitions and simplifies the function signature.


47-47: LGTM! Simplified data handling.

Directly returning the hits without transformation is appropriate since the backend now handles camelization with deep_camelize. This improves the separation of concerns and reduces frontend complexity.

backend/apps/owasp/migrations/0036_alter_projecthealthmetrics_score.py (1)

19-27: LGTM! Enhanced field validation and documentation.

The score field improvements are excellent:

  • null=True allows optional scores
  • Min/max validators (0.0-100.0) ensure data integrity
  • Descriptive help text improves field documentation
  • FloatField is appropriate for numeric scores

These changes enhance data validation and make the field more robust.

backend/tests/apps/owasp/scraper_test.py (1)

2-2: LGTM! Excellent modernization of HTTP status code usage.

The replacement of deprecated requests.codes with the standard library HTTPStatus enum improves code consistency and maintainability. All status code mappings are correct.

Note: The static analysis warning about HTTPStatus.IM_A_TEAPOT is a false positive - this is a valid HTTP status code (418) defined in the HTTPStatus enum.

Also applies to: 42-42, 49-49, 66-66, 70-70, 78-82, 96-96, 104-104, 113-113, 123-123, 133-133, 187-187

backend/apps/owasp/migrations/0037_alter_projecthealthmetrics_project.py (1)

13-21: Verify no code assumes a one-to-one relationship before merging

The migration correctly changes project from a OneToOneField to a ForeignKey—allowing multiple health metrics per project—adds on_delete=CASCADE, and defines related_name="health_metrics".

However, absence of grep matches for direct access patterns means you should manually audit any areas that might still assume a single health-metrics record, such as:

  • Direct attribute access like project.projecthealthmetrics
  • Queries using ProjectHealthMetrics.objects.get(project=…)
  • Serializer, view, or template code that treats a single object instead of a queryset
  • Any utility functions or business logic fetching a single health-metrics instance

Please review and update these references to use project.health_metrics (a queryset) or explicitly select the desired record.

backend/tests/apps/common/utils_test.py (1)

8-8: Excellent test coverage for the camelCase conversion utility.

The parameterized test provides comprehensive coverage of the convert_to_camel_case function, including edge cases with leading/trailing underscores, multiple consecutive underscores, and already camelCase strings.

Also applies to: 20-35

backend/apps/core/utils/index.py (1)

9-9: LGTM! Import addition aligns with utility usage.

The import is correctly added to support the new deep_camelize function.

backend/apps/owasp/migrations/0041_projecthealthrequirements_is_funding_requirements_compliant_and_more.py (1)

6-26: LGTM! Well-structured Django migration.

The migration correctly adds the compliance fields with appropriate defaults and verbose names. The dependency chain is proper and the field definitions align with the model requirements.

backend/apps/owasp/migrations/0042_alter_projecthealthmetrics_score.py (1)

7-27: LGTM! Proper score field configuration.

The migration correctly configures the score field with appropriate validators (0.0-100.0), nullable/blank settings, and descriptive help text. The field definition aligns with typical scoring requirements.

frontend/src/app/committees/page.tsx (4)

5-5: LGTM! Type import and PageLayout addition align with refactoring.

The unified Committee type import and PageLayout component addition support the codebase-wide standardization efforts.

Also applies to: 8-8


20-23: LGTM! Type parameter update supports unified types.

The change from CommitteeTypeAlgolia to Committee aligns with the broader effort to consolidate Algolia and GraphQL types into unified domain types.


25-52: LGTM! Property name updates follow camelCase convention.

The updates to updatedAt, relatedUrls, topContributors, and submitButton maintain consistency with frontend naming conventions.


55-70: LGTM! PageLayout wrapper provides consistent navigation.

The wrapping of SearchPageLayout within PageLayout provides consistent breadcrumb navigation across the application.

backend/apps/owasp/models/project_health_requirements.py (1)

27-32: LGTM! Well-defined compliance fields.

The new Boolean fields are properly configured with descriptive verbose names and appropriate default values. They align with the computed properties in the Project model (lines 146-155 in backend/apps/owasp/models/project.py) for a cohesive health requirements system.

backend/apps/owasp/migrations/0040_alter_projecthealthmetrics_is_leader_requirements_compliant.py (1)

6-22: Migration looks correct and follows Django conventions.

The field alteration is properly structured with appropriate default value and verbose name. The dependency chain is correct following the previous field rename.

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

5-6: LGTM! Consistent refactoring with improved conventions.

The changes align well with the broader frontend refactoring:

  • PageLayout wrapper for consistent navigation
  • camelCase naming conventions
  • Property name standardization

All changes improve code consistency and maintainability.

Also applies to: 32-32, 40-42, 45-45, 48-48, 54-70

backend/tests/apps/owasp/management/commands/owasp_update_project_health_requirements_test.py (1)

44-44: Test updates correctly reflect command implementation changes.

The transition from get_or_create to update_or_create and simplification of command invocation align with the updated management command behavior. Test structure and assertions remain comprehensive.

Also applies to: 47-47, 49-49, 54-54

backend/tests/apps/github/api/search/user_test.py (1)

1-88: Excellent comprehensive test coverage.

The test suite thoroughly covers the get_users function with well-structured test cases:

  • Default parameter behavior
  • Custom parameter handling
  • Edge cases with missing optional parameters
  • Proper mocking and assertion patterns

The tests ensure reliability of the GitHub user search API functionality.

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

7-8: LGTM: Type unification and PageLayout integration.

The updates to use the unified Chapter type and integrate PageLayout for consistent breadcrumb navigation are well-executed and align with the broader refactoring effort.

Also applies to: 12-12


51-53: LGTM: Consistent camelCase property naming.

The property name updates from snake_case to camelCase (updated_atupdatedAt, related_urlsrelatedUrls, top_contributorstopContributors) are consistent with the type system changes.

Also applies to: 72-73

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

5-6: LGTM: Consistent type unification and layout integration.

The updates follow the same pattern as other pages, using unified Organization type and PageLayout wrapper for consistent navigation.


40-40: LGTM: Property naming consistency.

The camelCase property updates (avatarUrl, followersCount, publicRepositoriesCount) maintain consistency with the unified type system.

Also applies to: 45-45, 49-49

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

5-5: LGTM: Type system unification.

The transition from ProjectTypeAlgolia to unified Project type and integration of PageLayout follows the established refactoring pattern consistently.

Also applies to: 10-10


35-35: LGTM: Consistent property naming updates.

The camelCase property updates (forksCount, starsCount, contributorsCount, topContributors, isActive) align well with the type system changes.

Also applies to: 51-51, 55-55

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

7-7: LGTM: Consistent type unification and layout pattern.

The updates to use unified Issue type and PageLayout wrapper complete the consistent refactoring pattern across all search pages.

Also applies to: 12-12


32-32: LGTM: Property naming consistency maintained.

The camelCase updates (createdAt, projectName, projectUrl) maintain consistency with the broader type system refactoring.

Also applies to: 53-54

backend/tests/apps/owasp/management/commands/owasp_update_project_health_metrics_scores_test.py (1)

20-34: Well-structured test setup with proper mocking.

The fixture setup properly patches the required dependencies and maintains clean test isolation. The context manager approach ensures proper cleanup.

backend/tests/apps/common/management/commands/generate_sitemap_test.py (1)

25-68: Well-structured individual sitemap tests.

The individual sitemap generation tests are well-organized and properly verify the expected behavior for each entity type.

backend/apps/owasp/admin.py (2)

167-189: Well-configured admin interface for ProjectHealthMetrics.

The admin configuration provides comprehensive functionality with appropriate filtering, search capabilities, and display fields that align well with the model structure.

The static analysis warning about "too few public methods" is a false positive - Django admin classes typically have minimal public methods as they rely on framework conventions.


186-188: Good defensive programming in custom method.

The project method properly handles the case where no project is associated, preventing potential errors in the admin interface.

backend/tests/apps/owasp/models/project_health_metrics_test.py (2)

99-118: Excellent addition of days calculation testing.

The new parameterized test for days calculation properties is well-structured and follows good testing practices by using a fixed date for consistent assertions.


10-10: Verify the DEFAULT_SCORE change aligns with model updates.

The change from 0.0 to None should align with the model's score field now allowing null values. This looks correct based on the AI summary mentioning the score field was updated to allow null and blank values.

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

3-4: Good type unification and import cleanup.

The removal of useMemo and adoption of the unified Chapter type simplifies the component and improves type safety.


62-68: Excellent use of optional chaining for geolocation data.

The optional chaining approach for accessing both _geoloc and geoLocation properties provides good fallback handling and prevents potential runtime errors.

frontend/src/types/committee.ts (2)

3-19: Excellent type unification with improved consistency.

The new unified Committee type with camelCase naming and optional fields provides better flexibility and consistency across the codebase. The use of the imported Contributor type maintains type safety.


8-8: All Committee usages already supply key and no breaks detected

– The committees listing page sources items from Algolia, where each record includes a key.
– The details page uses the committeeKey URL parameter (not committee.key) for routing and never accesses committee.key from the GraphQL response.
– There are no manual constructions of Committee objects without a key anywhere in the codebase.

backend/apps/owasp/management/commands/owasp_update_project_health_requirements.py (3)

17-18: Verify the boolean field defaults align with business requirements.

The new is_funding_requirements_compliant and is_leader_requirements_compliant fields have been added consistently across all project levels. Note that:

  • is_funding_requirements_compliant is True for all levels
  • is_leader_requirements_compliant is False for INCUBATOR but True for all other levels

Ensure these defaults align with OWASP project requirements policies.

Also applies to: 37-38, 57-58, 77-78


124-127: Good improvement using update_or_create.

The switch from get_or_create to update_or_create is more robust as it ensures existing requirements are updated with any new fields or changed defaults.


97-119: Ensure fallback requirements include all necessary fields.

The fallback requirements dictionary now includes the new boolean fields. However, verify that all fields present in the level-specific requirements are also included in the fallback to maintain consistency.

backend/apps/owasp/models/project_health_metrics.py (4)

17-21: Good change from OneToOneField to ForeignKey.

The change to ForeignKey with related_name="health_metrics" allows multiple health metrics per project, which provides more flexibility for tracking metrics over time.


71-103: Excellent implementation of computed properties with proper null handling.

The computed properties for days calculations are well-implemented:

  • Proper null checking prevents runtime errors
  • Consistent return type (int)
  • Clear naming and documentation
  • Using timezone.now() for current time

47-53: Verify score field validation aligns with requirements.

The score field now allows null/blank values with 0-100 range validation. Based on the retrieved learning, health metrics requirements should never be 0, and a requirement value of 0 should result in displaying 0 on charts. Ensure this null-allowed approach aligns with that requirement.


104-113: Well-implemented bulk save method following base class pattern.

The static bulk_save method correctly delegates to BulkSaveModel.bulk_save with proper type hints and documentation.

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

30-39: Path generation logic is correct and well-tested

The generateBreadcrumbsFromItems function always pairs each custom title with the corresponding URL segment path, and the auto-breadcrumb fallback correctly capitalizes segments when no custom items are provided. End-to-end tests already verify breadcrumbs on all page types (e.g., /about, /members, /projects, /organizations, etc.), confirming that titles and paths stay in sync across routes.

No changes required here.

backend/apps/owasp/models/project.py (1)

269-272: Unable to locate Issue model—please verify relationship and test filter logic

I wasn’t able to find a class Issue definition (and its assignees field) under backend/apps/owasp/models. Please:

• Confirm where your Issue model lives (e.g. backend/apps/owasp/models/issue.py) and that
assignees is declared as a ManyToManyField.
• Once located, verify in a Django shell or unit test that:
– Creating one issue with no assignees and another with at least one results in
project.unassigned_issues_count returning exactly the count of unassigned issues.

Comment on lines +102 to +110
- name: Copy crontab
copy:
src: '{{ github_workspace }}/cron/production'
dest: /tmp/production_crontab
mode: '0600'

- name: Install crontab
ansible.builtin.command:
cmd: crontab /tmp/production_crontab
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prefer idempotent cron deployment via copy + cron.d (or ansible.builtin.cron) instead of raw crontab

crontab /tmp/production_crontab will report changed on every run and makes it hard for Ansible to detect drift.
A more robust pattern is to drop a file in /etc/cron.d (or manage individual entries with the cron module).
Example diff:

-      - name: Copy crontab
-        copy:
-          src: '{{ github_workspace }}/cron/production'
-          dest: /tmp/production_crontab
-          mode: '0600'
-
-      - name: Install crontab
-        ansible.builtin.command:
-          cmd: crontab /tmp/production_crontab
+      - name: Install production cron entries
+        ansible.builtin.copy:
+          src: '{{ github_workspace }}/cron/production'
+          dest: /etc/cron.d/nest_production
+          owner: root
+          group: root
+          mode: '0644'
+        notify: Restart cron

Benefits:

  • Fully idempotent – file checksum drives change status.
  • Survives user changes to their personal crontab.
  • Avoids leaving sensitive files in /tmp.
  • Gives you a clear handler (Restart cron) for reloads.

If you must keep the personal‐crontab approach, consider:

  • creates: /var/spool/cron/{{ ansible_user_id }} on the command task.
  • Cleaning up /tmp/production_crontab afterwards.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Copy crontab
copy:
src: '{{ github_workspace }}/cron/production'
dest: /tmp/production_crontab
mode: '0600'
- name: Install crontab
ansible.builtin.command:
cmd: crontab /tmp/production_crontab
- name: Install production cron entries
ansible.builtin.copy:
src: '{{ github_workspace }}/cron/production'
dest: /etc/cron.d/nest_production
owner: root
group: root
mode: '0644'
notify: Restart cron
🤖 Prompt for AI Agents
In .github/ansible/production/nest.yaml around lines 102 to 110, replace the
current approach of copying the crontab file to /tmp and running `crontab`
command with an idempotent method by either placing the cron file in /etc/cron.d
using the `copy` module or managing cron entries with the `ansible.builtin.cron`
module. This avoids always reporting changes, prevents sensitive files in /tmp,
and ensures Ansible can detect drift properly. If you must keep the current
method, add a `creates` condition on the command task to prevent repeated runs
and clean up the temporary file afterward.

@@ -2,14 +2,14 @@ import { faCalendar, faFolderOpen, faCircleExclamation } from '@fortawesome/free
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useRouter } from 'next/navigation'
import React from 'react'
import { ProjectIssuesType } from 'types/project'
import type { Issue } from 'types/issue'
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify type compatibility for the Issue type change.

The component logic expects a repositoryName property (line 35, 42, 46), but the Issue type definition only has repository?: RepositoryDetails. This type mismatch could cause runtime errors.

Also applies to: 12-12


🏁 Script executed:

#!/bin/bash
# Search for repositoryName usage in Issue type and related components
rg -A 3 -B 3 "repositoryName" --type ts --type tsx

Length of output: 78


🏁 Script executed:

#!/bin/bash
# Search for repositoryName usage in TS and TSX files
rg -n "repositoryName" -t ts -t tsx

# Locate and print the Issue type definition
issue_file=$(rg -l -e '^export (interface|type) Issue' -t ts)
echo "Issue definition found in: $issue_file"
sed -n '1,200p' "$issue_file"

Length of output: 712


Fix missing repositoryName in the Issue type

RecentIssues.tsx is accessing item.repositoryName, but your Issue definition only has an optional repository?: RepositoryDetails and no repositoryName field. This mismatch will break the build or cause runtime errors.

Please update one of the following:

  • Option A: Add repositoryName: string (or repositoryName?: string) to frontend/src/types/issue.ts and ensure it’s populated by your data layer.
  • Option B: Change RecentIssues.tsx to read the repository name from item.repository?.name instead of item.repositoryName.

Affected locations:

  • frontend/src/components/RecentIssues.tsx (lines ~35, ~42, ~46)
  • frontend/src/types/issue.ts
🤖 Prompt for AI Agents
In frontend/src/components/RecentIssues.tsx at lines around 35, 42, and 46, the
code accesses item.repositoryName, but the Issue type in
frontend/src/types/issue.ts lacks this field, causing type errors. Fix this by
either adding a repositoryName field to the Issue type in
frontend/src/types/issue.ts and ensuring it is set in the data layer, or modify
RecentIssues.tsx to access the repository name via item.repository?.name instead
of item.repositoryName.

Comment on lines +187 to 203
if e.response["error"] == "ratelimited":
if retry_count >= max_retries:
self.stdout.write(
self.style.ERROR(f"Max retries ({max_retries}) exceeded for history")
)
break

retry_after = int(
e.response.headers.get("Retry-After", delay * (retry_count + 1))
)
retry_count += 1
self.stdout.write(
self.style.WARNING(f"Rate limited. Retrying after {retry_after} seconds")
)
time.sleep(retry_after)
continue
self.stdout.write(
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider extracting common retry logic to reduce code duplication.

The retry logic pattern is repeated across three methods with minor variations. Consider extracting this into a reusable method or decorator to improve maintainability.

Would you like me to propose a refactored implementation that extracts the common retry logic into a reusable pattern?

Also applies to: 278-299, 366-377

🤖 Prompt for AI Agents
In backend/apps/slack/management/commands/slack_sync_messages.py around lines
187 to 203 (and similarly at 278-299 and 366-377), the retry logic for handling
rate limits is duplicated with minor variations. Extract this retry logic into a
reusable method or decorator that accepts the function to retry and parameters
like max_retries and delay. Replace the duplicated code blocks with calls to
this new reusable retry handler to improve maintainability and reduce code
duplication.

Comment on lines +351 to +377
while retry_count < max_retries:
try:
time.sleep(delay)

user_info = client.users_info(user=slack_user_id)
self._handle_slack_response(user_info, "users_info")

author = Member.update_data(
user_info["user"], conversation.workspace, save=True
)
self.stdout.write(
self.style.SUCCESS(f"Created new member: {slack_user_id}")
)
break
except SlackApiError as e:
if e.response["error"] == "ratelimited":
retry_after = int(
e.response.headers.get("Retry-After", delay * (retry_count + 1))
)

retry_count += 1
self.stdout.write(
self.style.WARNING(
f"Rate limited on user info. Retrying after {retry_after}s"
)
)
time.sleep(retry_after)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Unnecessary initial delay before first API call.

The retry logic includes a delay before the first attempt to fetch user info, which is not needed and will slow down processing unnecessarily.

Move the delay to only occur on retries:

 while retry_count < max_retries:
     try:
-        time.sleep(delay)
-
         user_info = client.users_info(user=slack_user_id)
         self._handle_slack_response(user_info, "users_info")

         author = Member.update_data(
             user_info["user"], conversation.workspace, save=True
         )
         self.stdout.write(
             self.style.SUCCESS(f"Created new member: {slack_user_id}")
         )
         break
     except SlackApiError as e:
         if e.response["error"] == "ratelimited":
+            retry_count += 1
+            if retry_count >= max_retries:
+                break
+                
             retry_after = int(
                 e.response.headers.get("Retry-After", delay * (retry_count + 1))
             )
-
-            retry_count += 1
             self.stdout.write(
                 self.style.WARNING(
                     f"Rate limited on user info. Retrying after {retry_after}s"
                 )
             )
             time.sleep(retry_after)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while retry_count < max_retries:
try:
time.sleep(delay)
user_info = client.users_info(user=slack_user_id)
self._handle_slack_response(user_info, "users_info")
author = Member.update_data(
user_info["user"], conversation.workspace, save=True
)
self.stdout.write(
self.style.SUCCESS(f"Created new member: {slack_user_id}")
)
break
except SlackApiError as e:
if e.response["error"] == "ratelimited":
retry_after = int(
e.response.headers.get("Retry-After", delay * (retry_count + 1))
)
retry_count += 1
self.stdout.write(
self.style.WARNING(
f"Rate limited on user info. Retrying after {retry_after}s"
)
)
time.sleep(retry_after)
while retry_count < max_retries:
try:
user_info = client.users_info(user=slack_user_id)
self._handle_slack_response(user_info, "users_info")
author = Member.update_data(
user_info["user"], conversation.workspace, save=True
)
self.stdout.write(
self.style.SUCCESS(f"Created new member: {slack_user_id}")
)
break
except SlackApiError as e:
if e.response["error"] == "ratelimited":
retry_count += 1
if retry_count >= max_retries:
break
retry_after = int(
e.response.headers.get("Retry-After", delay * (retry_count + 1))
)
self.stdout.write(
self.style.WARNING(
f"Rate limited on user info. Retrying after {retry_after}s"
)
)
time.sleep(retry_after)
🤖 Prompt for AI Agents
In backend/apps/slack/management/commands/slack_sync_messages.py around lines
351 to 377, the code currently calls time.sleep(delay) before the first API call
inside the retry loop, causing an unnecessary initial delay. To fix this, remove
the initial time.sleep(delay) before the first attempt and instead place the
delay only before retry attempts after a failure. This means the first API call
happens immediately, and subsequent retries wait for the specified delay.

Comment on lines +1 to 8
export type Contributor = {
avatarUrl: string
contributionsCount: number
login: string
name: string
projectKey?: string
projectKey: string
projectName?: string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify that all data sources provide the required projectKey field.

The type unification and camelCase conversion improve consistency. However, making projectKey required (removing the ? optional marker) is a breaking change.

[approve_code_changes]

Ensure all contributor data sources provide the projectKey field:


🏁 Script executed:

#!/bin/bash
# Description: Verify all contributor data sources include projectKey

# Search for Contributor type usage and creation
rg -A 5 -B 2 "Contributor\[\]|: Contributor|as Contributor"

# Search for contributor data creation/mapping
rg -A 10 -B 2 "topContributors|contributors.*="

# Check API responses and mock data
fd -e ts -e tsx | xargs rg -l "contributorsCount|avatarUrl.*login"

Length of output: 120587


Ensure all topContributors queries include the required projectKey field

We’ve confirmed that while the Home query returns both projectKey and projectName, the other GraphQL queries for fetching topContributors do not include projectKey, which will break the now-required field on the Contributor type. Please update each query and any related mock/test data to supply projectKey (and optionally projectName) for every topContributors selection.

Affected queries (add projectKey and projectName to each selection set):

  • frontend/src/server/queries/committeeQueries.ts
  • frontend/src/server/queries/organizationQueries.ts
  • frontend/src/server/queries/projectQueries.ts
  • frontend/src/server/queries/repositoryQueries.ts
  • frontend/src/server/queries/chapterQueries.ts
  • frontend/src/server/queries/snapshotQueries.ts

Also:

  • Update any E2E/mock files under __tests__/e2e/data/ and unit mock data in __tests__/unit/data/ so they include projectKey for each contributor.
  • Verify that any utility mapping (e.g. in frontend/src/utils/data.ts) passes along projectKey.

Once these queries and mock definitions supply projectKey, the breaking change will be safe.

🤖 Prompt for AI Agents
In frontend/src/types/contributor.ts lines 1 to 8, the Contributor type now
requires the projectKey field, but several topContributors GraphQL queries do
not include it. Update the queries in
frontend/src/server/queries/committeeQueries.ts, organizationQueries.ts,
projectQueries.ts, repositoryQueries.ts, chapterQueries.ts, and
snapshotQueries.ts to add projectKey and optionally projectName to each
topContributors selection set. Also, update all related mock and test data files
under __tests__/e2e/data/ and __tests__/unit/data/ to include projectKey for
each contributor. Finally, verify and update any utility functions in
frontend/src/utils/data.ts to ensure projectKey is passed along correctly. This
will ensure the Contributor type requirements are met and prevent breaking
changes.

Comment on lines +6 to +8
export interface crumbItem {
title: string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type inconsistency with BreadCrumbItem interface.

The crumbItem interface only defines a title property, but BreadCrumbItem (used by the BreadCrumbs component) requires both title and path. This mismatch could lead to runtime issues.

Consider updating the interface to match:

export interface crumbItem {
  title: string
+ path?: string
}

Or better yet, reuse the existing BreadCrumbItem interface directly to ensure consistency.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export interface crumbItem {
title: string
}
export interface crumbItem {
title: string
path?: string
}
🤖 Prompt for AI Agents
In frontend/src/components/PageLayout.tsx around lines 6 to 8, the crumbItem
interface only defines a title property but BreadCrumbItem requires both title
and path, causing a type mismatch. Fix this by either updating crumbItem to
include both title and path properties or, preferably, replace crumbItem with
the existing BreadCrumbItem interface to maintain consistency and avoid runtime
issues.

Comment on lines +41 to +52
export default function PageLayout({ breadcrumbItems, children }: PageLayoutProps) {
const pathname = usePathname()
const isBreadCrumbItemsEmpty = _.isEmpty(breadcrumbItems)
let allBreadcrumbs: BreadCrumbItem[]
if (_.isArray(breadcrumbItems)) {
allBreadcrumbs = generateBreadcrumbsFromItems(breadcrumbItems, pathname)
} else {
const autoBreadcrumbs = generateAutoBreadcrumbs(pathname, !isBreadCrumbItemsEmpty)
allBreadcrumbs = isBreadCrumbItemsEmpty
? autoBreadcrumbs
: [...autoBreadcrumbs, { title: _.get(breadcrumbItems, 'title', ''), path: pathname }]
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify complex breadcrumb logic.

The current logic for handling single vs array breadcrumb items is overly complex and could be error-prone. The mixed handling of crumbItem and crumbItem[] types adds unnecessary complexity.

Consider simplifying to always work with arrays:

export interface PageLayoutProps {
- breadcrumbItems?: crumbItem | crumbItem[]
+ breadcrumbItems?: crumbItem[]
  children: React.ReactNode
}

export default function PageLayout({ breadcrumbItems = [], children }: PageLayoutProps) {
  const pathname = usePathname()
- const isBreadCrumbItemsEmpty = _.isEmpty(breadcrumbItems)
- let allBreadcrumbs: BreadCrumbItem[]
- if (_.isArray(breadcrumbItems)) {
-   allBreadcrumbs = generateBreadcrumbsFromItems(breadcrumbItems, pathname)
- } else {
-   const autoBreadcrumbs = generateAutoBreadcrumbs(pathname, !isBreadCrumbItemsEmpty)
-   allBreadcrumbs = isBreadCrumbItemsEmpty
-     ? autoBreadcrumbs
-     : [...autoBreadcrumbs, { title: _.get(breadcrumbItems, 'title', ''), path: pathname }]
- }
+ 
+ const allBreadcrumbs = _.isEmpty(breadcrumbItems)
+   ? generateAutoBreadcrumbs(pathname)
+   : generateBreadcrumbsFromItems(breadcrumbItems, pathname)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default function PageLayout({ breadcrumbItems, children }: PageLayoutProps) {
const pathname = usePathname()
const isBreadCrumbItemsEmpty = _.isEmpty(breadcrumbItems)
let allBreadcrumbs: BreadCrumbItem[]
if (_.isArray(breadcrumbItems)) {
allBreadcrumbs = generateBreadcrumbsFromItems(breadcrumbItems, pathname)
} else {
const autoBreadcrumbs = generateAutoBreadcrumbs(pathname, !isBreadCrumbItemsEmpty)
allBreadcrumbs = isBreadCrumbItemsEmpty
? autoBreadcrumbs
: [...autoBreadcrumbs, { title: _.get(breadcrumbItems, 'title', ''), path: pathname }]
}
export interface PageLayoutProps {
breadcrumbItems?: crumbItem[]
children: React.ReactNode
}
export default function PageLayout({ breadcrumbItems = [], children }: PageLayoutProps) {
const pathname = usePathname()
const allBreadcrumbs = _.isEmpty(breadcrumbItems)
? generateAutoBreadcrumbs(pathname)
: generateBreadcrumbsFromItems(breadcrumbItems, pathname)
return (
<div>
{/* render breadcrumbs */}
{children}
</div>
)
}
🤖 Prompt for AI Agents
In frontend/src/components/PageLayout.tsx around lines 41 to 52, the breadcrumb
handling logic is overly complex due to separate handling of single breadcrumb
items and arrays. Simplify by normalizing breadcrumbItems to always be an array
at the start of the function, then process it uniformly. This removes
conditional branches and makes the code easier to maintain and less error-prone.

Comment on lines +186 to +189
@property
def leaders_count(self) -> int:
"""Return the count of leaders."""
return len(self.leaders_raw)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix reference to undefined attribute.

The property references self.leaders_raw which doesn't appear to be defined in the model. This will cause an AttributeError at runtime.

#!/bin/bash
# Search for leaders_raw definition in the codebase
ast-grep --pattern 'leaders_raw = $_'
rg -A 3 "leaders_raw"
🤖 Prompt for AI Agents
In backend/apps/owasp/models/project.py around lines 186 to 189, the property
leaders_count references an undefined attribute self.leaders_raw, causing an
AttributeError. To fix this, identify the correct attribute or method that holds
the leaders data in the model and update the property to use that instead of
self.leaders_raw. If no such attribute exists, implement the logic to retrieve
the leaders collection properly before returning its length.

Comment on lines +171 to +174
@property
def issues_count(self) -> int:
"""Return count of issues."""
return self.issues.count()
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize database queries for count properties.

Multiple properties execute database queries on each access, which could lead to N+1 query problems when these properties are accessed frequently. Consider using cached values or database annotations.

For frequently accessed counts, consider:

  1. Database-level caching: Use Django's @cached_property decorator
  2. Aggregation at query time: Use select_related and prefetch_related when fetching projects
  3. Denormalized fields: Store computed counts in the database and update them periodically

Example for issues_count:

+from django.utils.functional import cached_property

-@property
+@cached_property
def issues_count(self) -> int:
    """Return count of issues."""
    return self.issues.count()

Or consider adding denormalized count fields to the model and updating them via signals or management commands.

Also applies to: 200-203, 219-222, 259-262, 264-267, 269-272

🤖 Prompt for AI Agents
In backend/apps/owasp/models/project.py around lines 171 to 174, the
issues_count property executes a database query each time it is accessed, which
can cause N+1 query problems. To fix this, convert the property to use Django's
@cached_property decorator to cache the count after the first access, or
alternatively, annotate the queryset with the count when fetching projects to
avoid repeated queries. For a more scalable solution, consider adding a
denormalized field to store the count in the database and update it via signals
or periodic tasks. Apply similar changes to the other count properties at lines
200-203, 219-222, 259-262, 264-267, and 269-272.

Comment on lines +150 to +155
@property
def is_leader_requirements_compliant(self) -> bool:
"""Indicate whether project is compliant with project leaders requirements."""
# https://owasp.org/www-committee-project/#div-practice
# Have multiple Project Leaders who are not all employed by the same company.
return self.leaders_count > 1
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Complete the leader requirements compliance logic.

The current implementation only checks if there are multiple leaders, but the comment indicates the requirement is "multiple Project Leaders who are not all employed by the same company." The company validation is missing.

@property
def is_leader_requirements_compliant(self) -> bool:
    """Indicate whether project is compliant with project leaders requirements."""
    # https://owasp.org/www-committee-project/#div-practice
    # Have multiple Project Leaders who are not all employed by the same company.
-   return self.leaders_count > 1
+   if self.leaders_count <= 1:
+       return False
+   
+   # TODO: Add company validation logic
+   # Check if leaders are from different companies
+   return True
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@property
def is_leader_requirements_compliant(self) -> bool:
"""Indicate whether project is compliant with project leaders requirements."""
# https://owasp.org/www-committee-project/#div-practice
# Have multiple Project Leaders who are not all employed by the same company.
return self.leaders_count > 1
@property
def is_leader_requirements_compliant(self) -> bool:
"""Indicate whether project is compliant with project leaders requirements."""
# https://owasp.org/www-committee-project/#div-practice
# Have multiple Project Leaders who are not all employed by the same company.
if self.leaders_count <= 1:
return False
# TODO: Add company validation logic
# Check if leaders are from different companies
return True
🤖 Prompt for AI Agents
In backend/apps/owasp/models/project.py around lines 150 to 155, the
is_leader_requirements_compliant property currently only checks if there are
multiple leaders but does not verify if they are employed by different companies
as required. Update the logic to ensure that there are multiple leaders and that
not all leaders belong to the same company by checking the distinct companies of
the leaders and confirming there is more than one unique company.

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
16 Security Hotspots

See analysis details on SonarQube Cloud

@codic-yeeshu codic-yeeshu marked this pull request as draft June 28, 2025 20:19
@codic-yeeshu
Copy link
Contributor Author

Hey @kasya ! I've created a cleaner PR to address this issue. The previous one had several conflicts, so I’ve consolidated all the fixes and enhancements into this new PR for clarity.

@arkid15r arkid15r closed this Jul 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve breadcrumbs component
9 participants