-
-
Notifications
You must be signed in to change notification settings - Fork 120
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
Conversation
Summary by CodeRabbit
Summary by CodeRabbit
WalkthroughThe 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
Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes found. Possibly related PRs
Suggested reviewers
✨ Finishing Touches
🧪 Generate Unit Tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 toBreadcrumbItem
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
📒 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()
toscreen.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
touser?.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 andorganizationKey
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>
elementfrontend/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.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works good! 👍🏼
Left some requests for naming, styling - and just general improvements.
type="chapter" | ||
/> | ||
<PageLayout | ||
bcItems={[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here - can we update this for a clearer naming? If it's conflicting with anything we can do something like crumbItem
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
|
||
interface BreadcrumbItem { | ||
title: string | ||
href: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think path
is more suitable here than href
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
/> | ||
<PageLayout | ||
bcItems={[ | ||
{ title: 'Organizations', href: '/organizations' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
Thank you for the feedback, @kasya . I’ll make the updates asap!. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 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
⛔ 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)
…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]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
🔭 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 theContributor
type uses camelCase properties (avatarUrl
,contributionsCount
). This type guard will always returnfalse
.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 orinclude_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:
- The return type annotation
dict | list
doesn't cover all possible return values (primitive types)- Consider handling other iterable types like tuples and sets
- 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 objfrontend/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 fromdjango.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 theuseMemo
hook means marker creation will happen on every render. IfgeoLocData
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
⛔ 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 bothnumber
andstring
inputs (Unix timestamps and ISO strings), so usingPullRequest.createdAt: string
alongsideIssue.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 newmax_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 newdelay
andmax_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 textbackend/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
toButton
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
tois_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_url
→avatarUrl
,collaborators_count
→collaboratorsCount
) 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 therequests
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
toAlgoliaResponse
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 libraryHTTPStatus
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 mergingThe migration correctly changes
project
from a OneToOneField to a ForeignKey—allowing multiple health metrics per project—addson_delete=CASCADE
, and definesrelated_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 andPageLayout
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
toCommittee
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
, andsubmitButton
maintain consistency with frontend naming conventions.
55-70
: LGTM! PageLayout wrapper provides consistent navigation.The wrapping of
SearchPageLayout
withinPageLayout
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 inbackend/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
toupdate_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 integratePageLayout
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_at
→updatedAt
,related_urls
→relatedUrls
,top_contributors
→topContributors
) 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 andPageLayout
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 unifiedProject
type and integration ofPageLayout
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 andPageLayout
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
toNone
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 unifiedChapter
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
andgeoLocation
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 importedContributor
type maintains type safety.
8-8
: All Committee usages already supplykey
and no breaks detected– The committees listing page sources items from Algolia, where each record includes a
key
.
– The details page uses thecommitteeKey
URL parameter (notcommittee.key
) for routing and never accessescommittee.key
from the GraphQL response.
– There are no manual constructions ofCommittee
objects without akey
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
andis_leader_requirements_compliant
fields have been added consistently across all project levels. Note that:
is_funding_requirements_compliant
isTrue
for all levelsis_leader_requirements_compliant
isFalse
for INCUBATOR butTrue
for all other levelsEnsure 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
toupdate_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
withrelated_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 toBulkSaveModel.bulk_save
with proper type hints and documentation.frontend/src/components/PageLayout.tsx (1)
30-39
: Path generation logic is correct and well-testedThe
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 locateIssue
model—please verify relationship and test filter logicI wasn’t able to find a
class Issue
definition (and itsassignees
field) underbackend/apps/owasp/models
. Please:• Confirm where your
Issue
model lives (e.g.backend/apps/owasp/models/issue.py
) and that
assignees
is declared as aManyToManyField
.
• 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.
- 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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 thecommand
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.
- 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' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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
(orrepositoryName?: string
) tofrontend/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 ofitem.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.
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( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
export type Contributor = { | ||
avatarUrl: string | ||
contributionsCount: number | ||
login: string | ||
name: string | ||
projectKey?: string | ||
projectKey: string | ||
projectName?: string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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 includeprojectKey
for each contributor. - Verify that any utility mapping (e.g. in
frontend/src/utils/data.ts
) passes alongprojectKey
.
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.
export interface crumbItem { | ||
title: string | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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 }] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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.
@property | ||
def leaders_count(self) -> int: | ||
"""Return the count of leaders.""" | ||
return len(self.leaders_raw) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
@property | ||
def issues_count(self) -> int: | ||
"""Return count of issues.""" | ||
return self.issues.count() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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:
- Database-level caching: Use Django's
@cached_property
decorator - Aggregation at query time: Use
select_related
andprefetch_related
when fetching projects - 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.
@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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
@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.
|
Resolves #1425