Skip to content

Conversation

@rudransh-shrivastava
Copy link
Collaborator

@rudransh-shrivastava rudransh-shrivastava commented Oct 10, 2025

Resolves #1431
This PR was closed and re-opened (#1772)

Proposed change

  • Extract Leaders component and use in about/chapter/project pages.
  • Expose EntityMember node in GraphQL.

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 10, 2025

Summary by CodeRabbit

  • New Features

    • Added Leaders sections to About, Project, and Chapter pages with profile navigation.
    • Details cards now display leaders when available via expanded API fields.
    • Projects show up to the top 5 leaders.
  • Refactor

    • Unified leaders fetching and rendering into a reusable component and hook, simplifying page implementations.
  • Tests

    • Added unit and end-to-end tests for Leaders sections on details pages and the standalone component.
    • Removed obsolete error-state tests related to prior leaders handling.

Walkthrough

Adds backend EntityMember APIs and GraphQL node; frontend introduces a Leaders component, threads entityLeaders through pages and CardDetailsPage, updates GraphQL queries/types, and adds unit and e2e tests and mocks.

Changes

Cohort / File(s) Summary
Backend GraphQL nodes
backend/apps/owasp/api/internal/nodes/common.py, backend/apps/owasp/api/internal/nodes/entity_member.py
Add EntityMemberNode relay node and expose entity_leaders field on GenericEntityNode with resolver returning EntityMember instances.
Backend models
backend/apps/owasp/models/common.py, backend/apps/owasp/models/project.py
Replace User-based entity_leaders with QuerySet[EntityMember]; add MAX_LEADERS_COUNT and entity_leaders property on Project limiting results.
Frontend Leaders UI & About page
frontend/src/components/Leaders.tsx, frontend/src/app/about/page.tsx, frontend/__tests__/unit/pages/About.test.tsx
New Leaders component; consolidate leaders loading via useLeadersData on About; remove per-user LeaderData usage and related tests/mocks adjustments.
Details pages & Card
frontend/src/app/chapters/[chapterKey]/page.tsx, frontend/src/app/projects/[projectKey]/page.tsx, frontend/src/components/CardDetailsPage.tsx
Pass entityLeaders prop into DetailsCard and render Leaders when provided.
Frontend GraphQL queries
frontend/src/server/queries/chapterQueries.ts, frontend/src/server/queries/projectQueries.ts, frontend/src/server/queries/userQueries.ts
Add entityLeaders { id, description, memberName, member { id, login, name, avatarUrl } } to chapter/project queries; remove company and location from leader user query.
Types & mocks
frontend/src/types/leader.ts, frontend/src/types/card.ts, frontend/src/types/chapter.ts, frontend/src/types/project.ts, frontend/__tests__/unit/data/mockChapterDetailsData.ts, frontend/__tests__/unit/data/mockProjectDetailsData.ts
Add Leader type and optional entityLeaders?: Leader[] to Card/Chapter/Project types; extend test mock data with entityLeaders.
Tests (frontend)
frontend/__tests__/e2e/pages/ChapterDetails.spec.ts, frontend/__tests__/e2e/pages/ProjectDetails.spec.ts, frontend/__tests__/unit/components/Leaders.test.tsx, frontend/__tests__/unit/components/CardDetailsPage.test.tsx, frontend/__tests__/unit/pages/ChapterDetails.test.tsx, frontend/__tests__/unit/pages/ProjectDetails.test.tsx
Add unit and e2e tests for Leaders rendering, content, and navigation; add Leaders unit tests; update CardDetailsPage tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • kasya

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Significant backend and GraphQL schema updates—including adding EntityMemberNode, modifying model properties for entity_leaders, and updating multiple resolver and query definitions—go beyond the UI-focused objectives of issue #1431 and do not appear in its scope. Consider splitting the backend and GraphQL schema changes into a separate pull request or clearly documenting their necessity in the issue to ensure the UI extraction remains focused and reviewable against the original objectives.
Title Check ❓ Inconclusive The provided title focuses on improving the chapter and project leaders presentation but contains a typo and omits mention of the GraphQL changes introduced in the pull request, making it only partially descriptive of the full scope of changes. Consider correcting the typo (“Improve” instead of “Impove”) and refining the title to clearly reflect both the UI extraction of the Leaders component and the addition of the EntityMember GraphQL node, for example “Improve leaders presentation and expose EntityMember in GraphQL”.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The pull request extracts the Leaders component and reuses it on the about page without altering its layout, adds a Leaders block to both chapter and project pages above the Top Contributors section, and the visual presentation aligns with the objectives defined in issue #1431.
Description Check ✅ Passed The description accurately summarizes the extraction of the Leaders component for multiple pages and the exposure of the EntityMember node in GraphQL, matching the actual changes without being off-topic.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a 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

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 3

🧹 Nitpick comments (3)
backend/apps/owasp/models/common.py (1)

118-124: Consider caching ContentType lookup.

The implementation correctly filters EntityMember objects, but ContentType.objects.get_for_model(self.__class__) is called on every property access. While ContentType queries are typically cached by Django, you could optimize further by storing the result at the class level or using select_related/prefetch_related at calling sites.

Example optimization at the calling site:

# When querying entities with leaders
entities = Entity.objects.prefetch_related(
    Prefetch('entitymember_set', 
             queryset=EntityMember.objects.filter(role=EntityMember.Role.LEADER))
)
frontend/src/app/about/page.tsx (1)

51-73: Consider batching leader queries for better performance.

The hook makes three separate GraphQL queries for leaders. While this works for the About page with its fixed set of leaders, batching these into a single query would reduce network overhead and improve load time.

You could create a backend query that accepts multiple logins:

query GetMultipleLeaders($logins: [String!]!) {
  users(logins: $logins) {
    id
    login
    name
    avatarUrl
  }
}

Then refactor the hook:

const useLeadersData = () => {
  const { data, loading, error } = useQuery(GetMultipleLeadersDocument, {
    variables: { logins: Object.keys(leaders) },
  })
  
  const formattedLeaders = (data?.users || []).map((user) => ({
    description: leaders[user.login],
    memberName: user.name || user.login,
    member: user,
  }))
  
  return { formattedLeaders, isLoading: loading }
}
frontend/src/components/Leaders.tsx (1)

28-41: Prefer stable identifiers over array index for React keys.

Line 30 uses key={index} which is an anti-pattern in React, as it can cause issues when the list is reordered or items are added/removed. Although the leaders list is likely stable, using a more stable identifier would be more robust.

Apply this diff:

-        {users.map((user, index) => (
+        {users.map((user) => (
           <UserCard
-            key={index}
+            key={user.member?.login || user.memberName}
             avatar={user.member?.avatarUrl}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cd192c and 89e5fac.

⛔ Files ignored due to path filters (4)
  • frontend/src/types/__generated__/chapterQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/graphql.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/userQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (16)
  • backend/apps/owasp/api/internal/nodes/common.py (1 hunks)
  • backend/apps/owasp/api/internal/nodes/entity_member.py (1 hunks)
  • backend/apps/owasp/models/common.py (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/app/about/page.tsx (4 hunks)
  • frontend/src/app/chapters/[chapterKey]/page.tsx (1 hunks)
  • frontend/src/app/projects/[projectKey]/page.tsx (1 hunks)
  • frontend/src/components/CardDetailsPage.tsx (3 hunks)
  • frontend/src/components/Leaders.tsx (1 hunks)
  • frontend/src/server/queries/chapterQueries.ts (1 hunks)
  • frontend/src/server/queries/projectQueries.ts (1 hunks)
  • frontend/src/server/queries/userQueries.ts (0 hunks)
  • frontend/src/types/card.ts (2 hunks)
  • frontend/src/types/chapter.ts (1 hunks)
  • frontend/src/types/leader.ts (1 hunks)
  • frontend/src/types/project.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/server/queries/userQueries.ts
🧰 Additional context used
🧬 Code graph analysis (9)
frontend/src/app/chapters/[chapterKey]/page.tsx (1)
backend/apps/owasp/api/internal/queries/chapter.py (1)
  • chapter (14-19)
backend/apps/owasp/models/common.py (2)
backend/apps/owasp/api/internal/nodes/common.py (1)
  • entity_leaders (16-18)
backend/apps/owasp/models/entity_member.py (2)
  • EntityMember (10-112)
  • Role (13-16)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
backend/apps/owasp/models/entity_member.py (1)
  • EntityMember (10-112)
frontend/src/types/project.ts (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
frontend/src/types/card.ts (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
backend/apps/owasp/api/internal/nodes/common.py (2)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
  • EntityMemberNode (22-25)
backend/apps/owasp/models/common.py (1)
  • entity_leaders (118-124)
frontend/src/components/Leaders.tsx (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
frontend/src/types/chapter.ts (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
frontend/src/app/about/page.tsx (2)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
backend/apps/github/api/internal/queries/user.py (1)
  • user (40-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
🔇 Additional comments (13)
frontend/src/server/queries/projectQueries.ts (1)

14-24: LGTM!

The entityLeaders query structure is well-defined and includes all necessary fields (id, description, memberName, and nested member object). This aligns with the Leader type definition shown in the relevant code snippets.

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

9-9: LGTM!

The type extension is straightforward and correctly imports the Leader type dependency. The optional entityLeaders property integrates cleanly with the existing DetailsCardProps interface.

Also applies to: 48-48

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

95-95: LGTM!

The entityLeaders prop forwarding is consistent with the chapter page implementation and properly integrates with the updated DetailsCard component.

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

2-2: LGTM!

The Chapter type extension properly imports the Leader type and adds the optional entityLeaders field, maintaining consistency with the Project type definition.

Also applies to: 7-7

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

4-4: LGTM!

The Project type extension is consistent with the Chapter type changes and properly integrates the Leader type.

Also applies to: 22-22

backend/apps/owasp/api/internal/nodes/common.py (1)

5-8: No change needed for RepositoryContributorNode import The import is used in the top_contributors method (lines 31 and 33).

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

225-225: Leaders usage is correct
The Leaders component defines a users prop and safely handles member being null via optional chaining and fallbacks.

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

1-9: LGTM!

The Leader type definition is clean and properly structured. The nullable member field appropriately handles cases where leader information exists but the corresponding user account may not.

frontend/src/server/queries/chapterQueries.ts (1)

20-30: LGTM!

The entityLeaders query extension is well-structured and properly retrieves all necessary fields for the Leader type, including the nested member object.

backend/apps/owasp/api/internal/nodes/entity_member.py (1)

1-25: LGTM!

The EntityMemberNode is properly structured. The member: UserNode | None field at line 25 will be auto-resolved by Strawberry-Django from the EntityMember model's foreign key relationship to User, so no explicit resolver is needed.

frontend/__tests__/unit/pages/About.test.tsx (2)

368-368: LGTM!

Adding the login field to the partial user data mock is correct, as the Leaders component uses user.member.login for navigation.


1-556: Error and edge-case tests remain
About.test.tsx still covers loading spinner, null project, GraphQL errors, partial user data, and LeadersList has its own tests—no missing coverage.

Likely an incorrect or invalid review comment.

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

17-23: Well-designed navigation fallback.

The handleButtonClick function properly handles both cases: navigating to a specific member profile when available, or falling back to search when only a name is known.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/app/about/page.tsx (1)

51-73: Error handling issue already flagged in previous review.

The useLeadersData hook still lacks error handling for the GraphQL queries, as noted in the previous review comment. Please address the error handling feedback from the earlier review.

🧹 Nitpick comments (1)
frontend/src/components/Leaders.tsx (1)

1-1: Use FontAwesome icon objects consistently.

The component imports faPersonWalkingArrowRight as an icon object and uses it correctly on line 26, but passes a string class name "fa-solid fa-right-to-bracket" to FontAwesomeIconWrapper on line 33. For consistency and better type safety, import and use the icon object instead.

Apply this diff to use consistent icon objects:

-import { faPersonWalkingArrowRight } from '@fortawesome/free-solid-svg-icons'
+import { faPersonWalkingArrowRight, faRightToBracket } from '@fortawesome/free-solid-svg-icons'

Then update the button icon:

             button={{
-              icon: <FontAwesomeIconWrapper icon="fa-solid fa-right-to-bracket" />,
+              icon: <FontAwesomeIconWrapper icon={faRightToBracket} />,
               label: 'View Profile',
               onclick: () => handleButtonClick(user),
             }}

Also applies to: 33-33

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89e5fac and 87afa73.

📒 Files selected for processing (11)
  • backend/apps/owasp/api/internal/nodes/common.py (1 hunks)
  • frontend/__tests__/e2e/pages/ChapterDetails.spec.ts (1 hunks)
  • frontend/__tests__/e2e/pages/ProjectDetails.spec.ts (1 hunks)
  • frontend/__tests__/unit/components/CardDetailsPage.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/Leaders.test.tsx (1 hunks)
  • frontend/__tests__/unit/data/mockChapterDetailsData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockProjectDetailsData.ts (1 hunks)
  • frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1 hunks)
  • frontend/src/app/about/page.tsx (4 hunks)
  • frontend/src/components/Leaders.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
frontend/__tests__/unit/pages/ChapterDetails.test.tsx (1)
frontend/src/app/chapters/[chapterKey]/page.tsx (1)
  • ChapterDetailsPage (14-76)
frontend/__tests__/unit/components/Leaders.test.tsx (1)
frontend/__tests__/unit/data/mockProjectDetailsData.ts (1)
  • mockProjectDetailsData (1-140)
frontend/src/components/Leaders.tsx (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
backend/apps/owasp/api/internal/nodes/common.py (2)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
  • EntityMemberNode (22-25)
backend/apps/owasp/models/common.py (1)
  • entity_leaders (118-124)
frontend/src/app/about/page.tsx (2)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
backend/apps/github/api/internal/queries/user.py (1)
  • user (40-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
🔇 Additional comments (9)
frontend/__tests__/e2e/pages/ChapterDetails.spec.ts (1)

59-63: LGTM!

The test correctly verifies the Leaders block presence and content, checking for the heading, leader name, and role.

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

293-300: LGTM!

The test correctly verifies the Leaders block rendering with proper assertions for the heading, leader name, and role.

frontend/__tests__/e2e/pages/ProjectDetails.spec.ts (1)

129-134: LGTM!

The test provides thorough verification of the Leaders block by selecting the specific user card and validating both the structure and content. This is more detailed than the chapter test, which is good.

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

134-141: LGTM!

The test correctly verifies Leaders block rendering with appropriate assertions for the section heading, leader name, and role.

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

785-802: LGTM!

The test correctly verifies that the Leaders component renders when entityLeaders prop is provided, with appropriate data structure and assertions.

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

23-34: LGTM!

The entityLeaders mock data is correctly structured with all required fields (description, memberName, member with id/login/name/avatarUrl), matching the Leader type definition.

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

24-35: LGTM!

The entityLeaders mock data is correctly structured, consistent with the project mock data, and includes all required fields for the Leader type.

backend/apps/owasp/api/internal/nodes/common.py (1)

15-18: Strawberry-django auto-converts EntityMember instances to EntityMemberNode. No explicit conversion needed.

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

1-52: LGTM! Well-structured test suite.

The test coverage is appropriate, with clear scenarios for rendering with data, empty state, and navigation. The mocks effectively isolate the component under test.

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 (1)
frontend/src/components/Leaders.tsx (1)

25-44: Consider handling the empty leaders case.

The component renders correctly, but if all leader queries fail and users is an empty array, it will display an empty SecondaryCard with just the "Leaders" title and no content. While this may be acceptable if rare, consider either:

  • Not rendering the card at all when users.length === 0
  • Showing a fallback message like "Leaders information unavailable"

Example conditional rendering:

+  if (users.length === 0) {
+    return null
+  }
+
   return (
     <SecondaryCard icon={faPersonWalkingArrowRight} title={<AnchorTitle title="Leaders" />}>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87afa73 and 5f4839c.

📒 Files selected for processing (4)
  • backend/apps/owasp/api/internal/nodes/common.py (1 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (2 hunks)
  • frontend/src/app/about/page.tsx (4 hunks)
  • frontend/src/components/Leaders.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/apps/owasp/api/internal/nodes/common.py
🧰 Additional context used
🧬 Code graph analysis (3)
frontend/src/app/about/page.tsx (2)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
frontend/src/app/global-error.tsx (1)
  • handleAppError (66-86)
frontend/__tests__/unit/pages/About.test.tsx (4)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
frontend/src/types/__generated__/projectQueries.generated.ts (2)
  • GetProjectMetadataDocument (37-37)
  • GetTopContributorsDocument (38-38)
frontend/__tests__/unit/data/mockProjectData.ts (1)
  • mockProjectData (1-26)
frontend/__tests__/unit/data/mockUserData.ts (1)
  • mockUserData (1-22)
frontend/src/components/Leaders.tsx (1)
frontend/src/types/leader.ts (1)
  • Leader (1-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
🔇 Additional comments (5)
frontend/__tests__/unit/pages/About.test.tsx (2)

368-368: LGTM!

The addition of the login field aligns with the expanded Leader data structure and ensures type consistency in the partial user data scenario.


557-588: LGTM!

The error handling test properly verifies that GraphQL errors for leader queries trigger error toasts via handleAppError. The mock implementation correctly isolates the error scenario for a specific leader while allowing other queries to succeed.

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

51-91: Well-structured hook with graceful error handling.

The useLeadersData hook properly implements the error handling approach discussed in past comments:

  • Errors are logged via handleAppError without blocking the page
  • Each leader query is independent
  • The page renders with whatever leaders loaded successfully

The .filter(Boolean) on line 83 correctly removes null/undefined users, resulting in an empty array if all queries fail.


144-145: LGTM!

Correctly integrates the leaders loading state into the overall page loading condition.

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

17-23: LGTM!

The navigation logic properly handles both cases:

  • Direct navigation to member profile when full member data exists
  • Fallback to search query when only memberName is available

The use of encodeURIComponent ensures special characters in names are properly handled.

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 (1)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)

19-19: Consider exposing role as a GraphQL enum for type safety.

The role field is currently exposed as a string, but the underlying EntityMember.Role is a Django TextChoices enum. Strawberry-Django can auto-convert choice fields to GraphQL enums, providing better type safety and auto-completion for clients.

You can create a Strawberry enum and reference it in the type decorator:

import strawberry
from apps.owasp.models.entity_member import EntityMember

@strawberry.enum
class EntityMemberRole(str, strawberry.enum.Enum):
    CANDIDATE = "candidate"
    LEADER = "leader"
    MEMBER = "member"

Then update the type decorator to map the role field:

 @strawberry_django.type(
     EntityMember,
     fields=[
         "description",
         "is_active",
         "is_reviewed",
         "member_email",
         "member_name",
         "order",
-        "role",
     ],
 )
 class EntityMemberNode(strawberry.relay.Node):
     """Entity member node."""
 
+    role: EntityMemberRole
     member: UserNode | None

Alternatively, if strawberry-django auto-converts enums in your configuration, you may only need to ensure the enum is importable and properly decorated.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f4839c and c523c7b.

📒 Files selected for processing (2)
  • backend/apps/owasp/api/internal/nodes/entity_member.py (1 hunks)
  • frontend/src/components/Leaders.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Leaders.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
backend/apps/owasp/models/entity_member.py (1)
  • EntityMember (10-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
🔇 Additional comments (1)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)

1-25: LGTM! Well-structured GraphQL node following strawberry-django patterns.

The implementation correctly:

  • Explicitly lists scalar fields to control API surface exposure
  • Separates the member FK as a custom UserNode | None field for proper type resolution
  • Inherits from strawberry.relay.Node for relay compliance with automatic ID handling
  • Matches the model's nullable member FK with the | None union type

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f4839c and e31ed65.

📒 Files selected for processing (2)
  • backend/apps/owasp/api/internal/nodes/entity_member.py (1 hunks)
  • frontend/src/components/Leaders.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Leaders.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
backend/apps/owasp/models/entity_member.py (1)
  • EntityMember (10-112)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run CI Denendencies Scan
  • GitHub Check: Run Code Scan
🔇 Additional comments (2)
backend/apps/owasp/api/internal/nodes/entity_member.py (2)

3-7: LGTM!

The imports are appropriate and necessary for defining the GraphQL node with nested user relationships.


10-21: Verify that exposing member_email is intentional.

The member_email field is exposed in the GraphQL API. Ensure this aligns with your privacy policy and that leader emails are intended to be publicly accessible. If emails should remain private, consider removing this field or adding access control.

Comment on lines +22 to +25
class EntityMemberNode(strawberry.relay.Node):
"""Entity member node."""

member: UserNode | None
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 10, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

LGTM! Verify dataloader usage for optimal performance.

The member relationship field is correctly typed as UserNode | None, matching the nullable foreign key in the EntityMember model. Strawberry Django should automatically resolve this relationship using a dataloader to avoid N+1 queries when fetching multiple leaders.

To confirm this optimization is working, verify that the generated GraphQL queries for lists of leaders (e.g., on chapter/project pages) batch the user lookups rather than issuing separate queries per leader.

Run the following script to check if strawberry_django dataloaders are configured in your schema:


🏁 Script executed:

#!/bin/bash
# Description: Check for dataloader configuration in the GraphQL schema setup

# Search for strawberry schema instantiation and dataloader config
rg -n --type=py -A 5 -B 2 'strawberry\.Schema|GraphQLView|GraphQLRouter' | head -50

Length of output: 1322


🏁 Script executed:

#!/bin/bash
# Inspect Schema instantiation and plugin configuration
rg -nP 'schema\s*=\s*strawberry\.Schema' -A5 -B5 backend/settings/graphql.py

# Check for plugins argument in the Schema call
rg -n 'plugins' -C3 backend/settings/graphql.py

# Search for any dataloader imports or decorators
rg -n 'dataloader' -C3 -g '*.py'

Length of output: 125


Configure DataLoaderPlugin in the Strawberry Schema

The schema instantiation in backend/settings/graphql.py (around line 43) is currently:

schema = strawberry.Schema(mutation=Mutation, query=Query)

Without the DataLoader plugin, member relationships won’t be batched, leading to N+1 queries. Update it to:

from strawberry.django.plugin import DjangoPlugin
from strawberry.dataloader import DataLoaderPlugin

schema = strawberry.Schema(
  query=Query,
  mutation=Mutation,
  plugins=[DjangoPlugin(), DataLoaderPlugin()],
)

This ensures all FK relations (like member) are fetched in batches.

🤖 Prompt for AI Agents
In backend/apps/owasp/api/internal/nodes/entity_member.py around lines 22 to 25
the EntityMemberNode has a member FK that will cause N+1 queries unless the
Strawberry schema is configured with the DataLoader plugin; update
backend/settings/graphql.py (around line 43) to import DjangoPlugin and
DataLoaderPlugin and instantiate the schema with plugins=[DjangoPlugin(),
DataLoaderPlugin()] (ensure the imports are added at the top) so FK relations
like member are batched.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

is this relevant to the current PR objective?

Copy link
Contributor

Choose a reason for hiding this comment

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

@rudransh-shrivastava, you're right to question this—it's not strictly required for the functional PR objective. The leaders block will work and display correctly without the DataLoader plugin configuration.

However, it's a performance consideration: without DataLoaders, when rendering multiple leaders on chapter/project pages, Django will issue separate database queries for each leader's member relationship (the N+1 query problem). This could impact page load times, especially for entities with many leaders.

Your options:

  1. Address it now (adds ~3 lines to backend/settings/graphql.py) to proactively prevent performance issues
  2. Defer to a follow-up if you want to keep this PR focused solely on the functional requirements

Would you like me to create a separate issue to track this performance optimization?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@arkid15r Hello, is this something we should consider? I assume the actual solution might be a bit more complex since DataLoaderPlugin import CR suggests, does not exist. DataLoader exists, but I'm not sure.

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Collaborator

Choose a reason for hiding this comment

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

@rudransh-shrivastava could you create an issue to look into this later? Thank you!

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 (1)
frontend/src/app/about/page.tsx (1)

308-348: Consider adding explicit return type for type safety.

The hook is well-implemented and functional. To improve type safety and documentation, consider adding an explicit return type.

Apply this diff to add an explicit return type:

+interface LeadersDataResult {
+  leadersData: Array<{
+    description: string
+    memberName: string
+    member: {
+      id: string
+      avatarUrl: string
+      login: string
+      name?: string | null
+    }
+  }>
+  isLoading: boolean
+}
+
-const useLeadersData = () => {
+const useLeadersData = (): LeadersDataResult => {
   const {
     data: leader1Data,
     loading: loading1,
     error: error1,
   } = useQuery(GetLeaderDataDocument, {
     variables: { key: 'arkid15r' },
   })

This makes the return type explicit and helps catch type mismatches early.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e31ed65 and 218efdb.

📒 Files selected for processing (1)
  • frontend/src/app/about/page.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/app/about/page.tsx (2)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
frontend/src/app/global-error.tsx (1)
  • handleAppError (66-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
🔇 Additional comments (1)
frontend/src/app/about/page.tsx (1)

333-337: LGTM! Error handling correctly implemented.

The error handling implementation matches the solution from previous discussions:

  • ✅ Errors are logged individually via handleAppError
  • ✅ Page continues to render with available leaders (graceful degradation)
  • isLoading reflects actual loading state, not errors
  • ✅ Dependency array is correct

This provides a good user experience where leader query failures don't block the entire About page.

@rudransh-shrivastava rudransh-shrivastava marked this pull request as ready for review October 10, 2025 13:48
@rudransh-shrivastava rudransh-shrivastava force-pushed the feature/leaders-presentation branch from 2b3a33f to fa340f7 Compare October 10, 2025 16:08
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 (1)
frontend/__tests__/unit/data/mockChapterDetailsData.ts (1)

22-33: LGTM! Consider adding a multi-leader test scenario.

The entityLeaders structure is correct and provides basic test coverage for the Leaders component.

To improve test coverage for rendering multiple leaders, consider adding a second leader to the array:

     entityLeaders: [
       {
         description: 'Chapter Leader',
         memberName: 'Bob',
         member: {
           id: '2',
           login: 'bob',
           name: 'Bob',
           avatarUrl: 'https://avatars.githubusercontent.com/u/67890?v=4',
         },
       },
+      {
+        description: 'Co-Leader',
+        memberName: 'Alice',
+        member: {
+          id: '3',
+          login: 'alice',
+          name: 'Alice',
+          avatarUrl: 'https://avatars.githubusercontent.com/u/12345?v=4',
+        },
+      },
     ],

This ensures the Leaders component correctly handles multiple entries in the UI.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 218efdb and fa340f7.

⛔ Files ignored due to path filters (2)
  • frontend/src/types/__generated__/chapterQueries.generated.ts is excluded by !**/__generated__/**
  • frontend/src/types/__generated__/projectQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (4)
  • frontend/__tests__/unit/data/mockChapterDetailsData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockProjectDetailsData.ts (1 hunks)
  • frontend/src/server/queries/chapterQueries.ts (1 hunks)
  • frontend/src/server/queries/projectQueries.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/tests/unit/data/mockProjectDetailsData.ts
  • frontend/src/server/queries/projectQueries.ts
  • frontend/src/server/queries/chapterQueries.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests

@sonarqubecloud
Copy link

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Good foundation to build on, let's fix the details later.

I'm merging this, thank you 👍

@arkid15r arkid15r enabled auto-merge October 12, 2025 18:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/apps/owasp/api/internal/nodes/common.py (1)

13-16: Convert QuerySet to list in entity_leaders resolver.

backend/apps/owasp/api/internal/nodes/common.py lines 13–16:

-    return self.entity_leaders
+    return list(self.entity_leaders)
🧹 Nitpick comments (1)
frontend/src/app/about/page.tsx (1)

308-348: Error handling implemented correctly per previous discussion.

The error handling implementation matches the approach discussed in the previous review thread:

  • ✅ Each query properly destructures its error value
  • useEffect handles errors individually without blocking the page
  • ✅ Dependency array correctly includes [error1, error2, error3]
  • filter(Boolean) enables graceful degradation when queries fail
  • ✅ Loading state only reflects actual loading, not error states

The implementation allows the page to render successfully with partial leader data if some queries fail while still reporting errors via handleAppError.

Optional: Add explicit return type for clarity.

Consider adding an explicit return type annotation to improve documentation and catch potential type mismatches:

+import type { Leader } from 'types/leader'
+
-const useLeadersData = () => {
+const useLeadersData = (): { leadersData: Leader[]; isLoading: boolean } => {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa340f7 and f7c3fa2.

📒 Files selected for processing (4)
  • backend/apps/owasp/api/internal/nodes/common.py (1 hunks)
  • backend/apps/owasp/models/common.py (1 hunks)
  • backend/apps/owasp/models/project.py (3 hunks)
  • frontend/src/app/about/page.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
backend/apps/owasp/models/common.py (3)
backend/apps/owasp/api/internal/nodes/common.py (1)
  • entity_leaders (14-16)
backend/apps/owasp/models/project.py (1)
  • entity_leaders (134-136)
backend/apps/owasp/models/entity_member.py (2)
  • EntityMember (10-112)
  • Role (13-16)
frontend/src/app/about/page.tsx (2)
frontend/src/types/__generated__/userQueries.generated.ts (1)
  • GetLeaderDataDocument (26-26)
frontend/src/app/global-error.tsx (1)
  • handleAppError (66-86)
backend/apps/owasp/models/project.py (3)
backend/apps/owasp/models/entity_member.py (1)
  • EntityMember (10-112)
backend/apps/owasp/api/internal/nodes/common.py (1)
  • entity_leaders (14-16)
backend/apps/owasp/models/common.py (1)
  • entity_leaders (93-101)
backend/apps/owasp/api/internal/nodes/common.py (3)
backend/apps/owasp/api/internal/nodes/entity_member.py (1)
  • EntityMemberNode (22-25)
backend/apps/owasp/models/common.py (1)
  • entity_leaders (93-101)
backend/apps/owasp/models/project.py (1)
  • entity_leaders (134-136)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
backend/apps/owasp/models/project.py (1)

31-36: LGTM! Clean implementation with proper type hinting.

The TYPE_CHECKING import correctly handles the circular dependency, and the MAX_LEADERS_COUNT constant provides clear configurability. The QuerySet slicing is efficient and will be optimized by Django's ORM at the SQL level.

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

92-101: LGTM! Correct implementation of entity leaders filtering.

The property correctly filters EntityMember instances with appropriate conditions (active, reviewed, LEADER role) and maintains display order. The change from User-based to EntityMember-based leaders aligns with the PR objectives.

@arkid15r arkid15r added this pull request to the merge queue Oct 12, 2025
Merged via the queue into OWASP:main with commit 13eba9b Oct 12, 2025
26 checks passed
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.

Impove chapter/project leaders presentation

2 participants