Add reusable Contribution Heatmap to member page for design consistency#3298
Add reusable Contribution Heatmap to member page for design consistency#3298arkid15r merged 26 commits intoOWASP:mainfrom
Conversation
WalkthroughAdds persisted per-day contribution data to User, exposes it via GraphQL, introduces a management command to populate contribution_data, replaces inline member heatmap with the reusable ContributionHeatmap (adding a "medium" variant), updates queries/tests, and adds related migrations and Makefile adjustments. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/__tests__/unit/pages/UserDetails.test.tsx (2)
61-68: Consider accepting props in the mock for better test coverage.The mock ContributionHeatmap component currently ignores all props. While this simplifies testing, it means tests cannot verify that correct data (contributionData, startDate, endDate, variant) is passed to the component.
💡 Optional enhancement to verify props
jest.mock('components/ContributionHeatmap', () => { - const MockContributionHeatmap = () => <div data-testid="contribution-heatmap">Heatmap</div> + const MockContributionHeatmap = ({ contributionData, startDate, endDate, variant }: any) => ( + <div + data-testid="contribution-heatmap" + data-start-date={startDate} + data-end-date={endDate} + data-variant={variant} + data-contribution-count={Object.keys(contributionData || {}).length} + > + Heatmap + </div> + ) MockContributionHeatmap.displayName = 'MockContributionHeatmap' return { __esModule: true, default: MockContributionHeatmap, } })This would allow tests to assert on the props passed to the component, e.g.,
expect(heatmap).toHaveAttribute('data-variant', 'medium').
81-87: Mock data includes unused fields.The mock data includes a
yearsarray andintensityfield on contributions, but the actual page component (lines 56-69 in page.tsx) only uses thecontributionsarray and specifically thedateandcountfields. Theyearsandintensityfields appear to be unused.Consider simplifying the mock to only include fields that are actually used:
;(fetchHeatmapData as jest.Mock).mockResolvedValue({ - years: [{ year: '2023' }], contributions: [ { date: '2023-01-01', count: 5 }, - { date: '2023-01-02', count: 3, intensity: '1' }, + { date: '2023-01-02', count: 3 }, ], })
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
frontend/__tests__/unit/pages/UserDetails.test.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/components/ContributionHeatmap.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-07-13T11:34:31.823Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.
Applied to files:
frontend/src/app/members/[memberKey]/page.tsx
🔇 Additional comments (7)
frontend/src/components/ContributionHeatmap.tsx (3)
252-252: LGTM!Clean addition of the 'medium' variant to the type union. The variant remains optional with a sensible default.
276-294: LGTM!The medium variant width calculation follows a logical progression:
- Compact: 13.4px/week, 400px min
- Medium: 15.5px/week, 500px min
- Default: 19.5px/week, 600px min
The dependency array is correctly updated to use
variantinstead of the removedisCompactvariable.
325-325: LGTM!Height calculation correctly implements the three-tier sizing:
- Compact: 150px
- Medium: 172px
- Default: 195px
The chained ternary is appropriate here for straightforward value selection.
frontend/src/app/members/[memberKey]/page.tsx (4)
6-6: LGTM!The refactored state management is cleaner and aligns well with the ContributionHeatmap API:
contributionDataas a date-to-count map- Separate
dateRangefor start/end dates- Removal of
useThemeanduseRefsimplifies the componentAlso applies to: 16-16, 21-26
56-70: Data transformation logic is sound.The implementation correctly:
- Validates the contributions array
- Transforms to a date-count map
- Derives date range from sorted dates (ISO format sort works correctly)
The conditional check on line 63 ensures the date range is only set when contributions exist, preventing edge case issues.
154-154: LGTM!Adding
overflow-x-autoenables horizontal scrolling for long usernames, multiple badges, and the heatmap on smaller screens. This improves responsive design.
179-194: LGTM!The conditional rendering logic is thorough and correct:
- Validates user is not a private contributor
- Ensures contribution data exists and is non-empty
- Verifies date range is valid before rendering
Props passed to ContributionHeatmap match the component's interface, and the "medium" variant is appropriate for this layout context.
77158bc to
6bba723
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/app/members/[memberKey]/page.tsx (1)
49-73: Removeuserfrom dependency array to prevent double-fetching.The
uservariable is not used inside this useEffect, but including it in the dependency array causesfetchDatato run twice: once on mount (whenuserisundefined) and again when the GraphQL query completes (whenuserbecomes defined).🐛 Proposed fix
- }, [memberKey, user]) + }, [memberKey])
🧹 Nitpick comments (1)
frontend/src/components/ContributionHeatmap.tsx (1)
325-325: Consider a lookup object for variant dimensions.The nested ternary works but a lookup object would be more maintainable as variants grow:
♻️ Optional refactor
+const VARIANT_HEIGHT = { compact: 150, medium: 172, default: 195 } as const + // Then in the component: - height={variant === 'compact' ? 150 : variant === 'medium' ? 172 : 195} + height={VARIANT_HEIGHT[variant]}
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
frontend/__tests__/unit/pages/UserDetails.test.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/components/ContributionHeatmap.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/tests/unit/pages/UserDetails.test.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-13T11:34:31.823Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.
Applied to files:
frontend/src/app/members/[memberKey]/page.tsx
🔇 Additional comments (3)
frontend/src/components/ContributionHeatmap.tsx (1)
252-252: LGTM! Clean variant extension with consistent sizing.The
mediumvariant is well-positioned betweencompactanddefaultwith proportional width/height scaling. The dependency array correctly tracks bothheatmapSeriesandvariant.Also applies to: 276-294
frontend/src/app/members/[memberKey]/page.tsx (2)
56-70: LGTM! Data transformation is correctly implemented.The transformation from array to
Record<string, number>is clean, and the date range extraction with ISO string sorting works correctly. The empty array case is implicitly handled by the conditional checks at render time.
179-194: LGTM! Defensive rendering with proper guards.All edge cases are handled: private contributor check, empty data check, and date range validation. The
overflow-x-autocontainer ensures the heatmap scrolls gracefully on smaller viewports.
6bba723 to
a736195
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
frontend/__tests__/unit/pages/UserDetails.test.tsx (1)
82-87: Verify if theyearsfield in the mock is necessary.The mock returns both
yearsandcontributions, but the page component (lines 56-70) only appears to use thecontributionsarray. Theyearsfield might be unused mock data.Consider verifying whether
yearsis used elsewhere, and if not, simplify the mock:♻️ Potential simplification if years is unused
;(fetchHeatmapData as jest.Mock).mockResolvedValue({ - years: [{ year: '2023' }], contributions: [ { date: '2023-01-01', count: 5, intensity: '2' }, { date: '2023-01-02', count: 3, intensity: '1' }, ], })frontend/src/app/members/[memberKey]/page.tsx (1)
56-70: Verify browser support forArray.at()or consider a fallback.Line 67 uses
Array.at(-1)which is an ES2022 feature. While Next.js 16 and React 19 should support this, verify that your target browser matrix includes ES2022 support.If broader browser support is needed, consider this alternative:
♻️ Alternative using traditional array indexing
if (result.contributions.length > 0) { const dates = result.contributions.map((c) => c.date).sort((a, b) => a.localeCompare(b)) setDateRange({ startDate: dates[0], - endDate: dates.at(-1) ?? '', + endDate: dates[dates.length - 1] ?? '', }) }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
frontend/__tests__/unit/pages/UserDetails.test.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/components/ContributionHeatmap.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/components/ContributionHeatmap.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-07-13T11:34:31.823Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:14-14
Timestamp: 2025-07-13T11:34:31.823Z
Learning: In the Next.js frontend mentorship application, there are two distinct types for authentication-related data: ExtendedSession for useSession hook (containing accessToken and user.login properties) and UserRolesData for useUserRoles hook (containing currentUserRoles.roles array). The correct access pattern for GitHub username is `(session as ExtendedSession)?.user?.login`.
Applied to files:
frontend/src/app/members/[memberKey]/page.tsx
🔇 Additional comments (8)
frontend/__tests__/unit/pages/UserDetails.test.tsx (4)
8-8: LGTM!The import aligns with the mock setup below and the updated page implementation.
61-68: LGTM!The mock implementation is appropriately minimal for page-level testing. The
data-testidallows tests to verify the component renders without testing its internal implementation details.
279-300: LGTM!The test correctly verifies that the ContributionHeatmap component renders when valid data is available. The use of
waitForaccounts for the asynchronous data fetching in theuseEffect.
302-315: LGTM!The test appropriately verifies that the heatmap doesn't render when
fetchHeatmapDatareturns null. UsingqueryByTestIdfor negative assertions is the correct pattern.frontend/src/app/members/[memberKey]/page.tsx (4)
6-6: LGTM!All new imports are necessary for the refactored heatmap functionality and align with the PR objectives.
Also applies to: 13-13, 16-16
21-25: LGTM!The state declarations are well-typed and appropriately initialized. Empty defaults work correctly with the conditional rendering logic below.
154-154: LGTM!Adding
overflow-x-autoimproves mobile responsiveness by allowing horizontal scrolling when the heatmap is wider than the viewport. This prevents layout breaking on smaller screens.
179-194: Verify thevariant="medium"prop value.The code passes
variant="medium"to ContributionHeatmap. According to the AI summary, the component now supports'default' | 'medium' | 'compact'variants, so this should be valid. However, since the ContributionHeatmap component file isn't included in this review, please verify that "medium" is correctly implemented and produces the desired visual result.The conditional rendering logic is excellent—multiple checks ensure the component only renders with complete, valid data.
arkid15r
left a comment
There was a problem hiding this comment.
It looks like it still uses the 3rd party data fetching instead of our local data. The idea is to get rid of both external dependency and components code related to that. We want it to fetch our DB for user contributions data. It means it also needs to be update to day on a daily basis.
c1a6363 to
7953acb
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @backend/apps/github/management/commands/github_aggregate_contributions.py:
- Around line 34-45: The default for batch size is inconsistent: the
parser.add_argument("--batch-size") sets default=100 but in handle(...) the code
reads options.get("batch_size", 1000); change one to match the other. Either
update parser.add_argument to default=1000 or change options.get("batch_size",
100) in the github_aggregate_contributions.Command.handle method so that the
parser default and the handle fallback use the same value, and ensure the
variable name batch_size remains used consistently.
- Around line 102-113: The current Commit queryset groups by the full datetime
because it uses .values("created_at").annotate(count=Count("id")), so change it
to truncate created_at to date at DB level (use TruncDate on Commit.created_at
in the queryset and .values("date")/.annotate(count=Count("id"))), then use that
truncated date when building date_str; apply the same TruncDate pattern to the
prs and issues queries so all three aggregate by date instead of full datetime
for correct and efficient grouping.
In
@backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py:
- Around line 286-293: The loop verifying YYYY-MM-DD treats the datetime as
timezone-aware by calling datetime.strptime(date_str,
"%Y-%m-%d").astimezone(UTC), which forces a local-TZ assumption on a naive
datetime; simply remove the .astimezone(UTC) call and validate the format with
datetime.strptime(date_str, "%Y-%m-%d") (or use
datetime.fromisoformat(date_str)) and keep the subsequent length and
dash-position assertions on result.
🧹 Nitpick comments (4)
backend/tests/apps/github/api/internal/nodes/user_test.py (1)
313-338: Tests verify mock behavior rather than actual field resolution.These tests only verify that
mock_user.contribution_datareturns what was assigned to it, which tests the mock itself rather than theUserNodefield resolution. Compare with other tests in this file (e.g.,test_created_at_field,test_issues_count_field) that callUserNode.field_name(mock_user)to test actual resolver behavior.Since
contribution_datais a passthrough field (no custom resolver), this is acceptable but provides limited value. The real validation happens in thetest_meta_configurationtest above.frontend/src/components/ContributionHeatmap.tsx (2)
273-294: LGTM! Consistent width calculation pattern.The medium variant follows the established pattern with appropriate pixel-per-week (16) and padding (45) values that fall between compact and default. The minimum width of 500px is sensible.
One minor observation: consider extracting the magic numbers (pixelPerWeek, padding, minWidth) into a configuration object for each variant to improve maintainability.
♻️ Optional: Extract variant configuration
const VARIANT_CONFIG = { compact: { pixelPerWeek: 13.4, padding: 40, minWidth: 400 }, medium: { pixelPerWeek: 16, padding: 45, minWidth: 500 }, default: { pixelPerWeek: 19.5, padding: 50, minWidth: 600 }, } as const // Then in useMemo: const config = VARIANT_CONFIG[variant] const calculatedWidth = weeksCount * config.pixelPerWeek + config.padding return Math.max(config.minWidth, calculatedWidth)
298-302: Consider memoizinggetChartHeight.
getChartHeightis defined as a function inside the component and will be recreated on every render. Since it only depends onvariant, it could be memoized or converted to a simple lookup.♻️ Optional: Convert to memoized value or constant lookup
- const getChartHeight = () => { - if (variant === 'compact') return 150 - if (variant === 'medium') return 172 - return 195 - } + const chartHeight = useMemo(() => { + const heights = { compact: 150, medium: 172, default: 195 } + return heights[variant] + }, [variant])Then use
chartHeightdirectly instead ofgetChartHeight()on line 331.backend/apps/github/management/commands/github_aggregate_contributions.py (1)
66-76: Consider usingbulk_updateinstead of individual saves for better performance.Currently, each user is saved individually inside the loop, resulting in one DB write per user. For large datasets, using
bulk_updatein batches would significantly improve performance.♻️ Proposed refactor using bulk_update
processed = 0 users_to_update = [] for user in users.iterator(chunk_size=batch_size): contribution_data = self._aggregate_user_contributions(user, start_date) if contribution_data: user.contribution_data = contribution_data users_to_update.append(user) processed += 1 if len(users_to_update) >= batch_size: User.objects.bulk_update(users_to_update, ["contribution_data"]) users_to_update = [] self.stdout.write(f"Processed {processed}/{total_users} users...") # Save remaining users if users_to_update: User.objects.bulk_update(users_to_update, ["contribution_data"])
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
frontend/src/types/__generated__/graphql.tsis excluded by!**/__generated__/**frontend/src/types/__generated__/userQueries.generated.tsis excluded by!**/__generated__/**
📒 Files selected for processing (15)
backend/Makefilebackend/apps/github/Makefilebackend/apps/github/api/internal/nodes/user.pybackend/apps/github/management/commands/github_aggregate_contributions.pybackend/apps/github/migrations/0041_user_contribution_data.pybackend/apps/github/models/user.pybackend/tests/apps/github/api/internal/nodes/user_test.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/tests/apps/github/models/user_test.pyfrontend/__tests__/mockData/mockUserDetails.tsfrontend/__tests__/unit/components/ContributionHeatmap.test.tsxfrontend/__tests__/unit/pages/UserDetails.test.tsxfrontend/src/app/members/[memberKey]/page.tsxfrontend/src/components/ContributionHeatmap.tsxfrontend/src/server/queries/userQueries.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/app/members/[memberKey]/page.tsx
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-12-31T05:17:39.659Z
Learnt from: kart-u
Repo: OWASP/Nest PR: 3101
File: backend/apps/common/extensions.py:92-98
Timestamp: 2025-12-31T05:17:39.659Z
Learning: In this codebase, import OperationType for GraphQL operations from the graphql-core package rather than from strawberry. Use 'from graphql import OperationType'. Strawberry re-exports via graphql-core internally, so relying on strawberry's API may be brittle. Apply this rule to all Python files that deal with GraphQL operation types; ensure imports come from graphql (graphql-core) and not from strawberry packages. This improves compatibility and avoids coupling to strawberry's internals.
Applied to files:
backend/apps/github/migrations/0041_user_contribution_data.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/tests/apps/github/models/user_test.pybackend/apps/github/api/internal/nodes/user.pybackend/apps/github/models/user.pybackend/tests/apps/github/api/internal/nodes/user_test.pybackend/apps/github/management/commands/github_aggregate_contributions.py
📚 Learning: 2026-01-01T17:48:23.963Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:41-47
Timestamp: 2026-01-01T17:48:23.963Z
Learning: In Django code, be aware that a QuerySet's boolean evaluation (e.g., if not queryset) runs a database query to determine emptiness. While it is technically valid to use the queryset in a boolean context, use queryset.exists() for existence checks to avoid unnecessary queries and improve performance. Applicable broadly to Python/Django files rather than just this specific path.
Applied to files:
backend/apps/github/migrations/0041_user_contribution_data.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/tests/apps/github/models/user_test.pybackend/apps/github/api/internal/nodes/user.pybackend/apps/github/models/user.pybackend/tests/apps/github/api/internal/nodes/user_test.pybackend/apps/github/management/commands/github_aggregate_contributions.py
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.
Applied to files:
frontend/__tests__/unit/pages/UserDetails.test.tsx
📚 Learning: 2025-12-18T05:39:42.678Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:40-40
Timestamp: 2025-12-18T05:39:42.678Z
Learning: In Django management commands, prefer using self.stdout.write(...) over print(...) for user-facing stdout output. This aligns with Django conventions and improves testability. When emitting messages, consider using self.stdout.write and, for styled messages, use self.style.SUCCESS/ERROR as appropriate to maintain consistent command output formatting. Apply this guideline to all Python files within any project's management/commands directory.
Applied to files:
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/apps/github/management/commands/github_aggregate_contributions.py
🧬 Code graph analysis (3)
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (1)
backend/apps/github/management/commands/github_aggregate_contributions.py (2)
_aggregate_user_contributions(82-141)handle(41-80)
backend/tests/apps/github/models/user_test.py (1)
backend/apps/github/models/user.py (1)
User(28-223)
backend/apps/github/management/commands/github_aggregate_contributions.py (1)
backend/apps/github/models/commit.py (1)
Commit(11-110)
🔇 Additional comments (24)
frontend/src/server/queries/userQueries.ts (1)
88-88: LGTM!The
contributionDatafield is correctly added to the GraphQL query, enabling the frontend to fetch per-day contribution counts for the heatmap component.backend/Makefile (1)
159-159: LGTM!The
github-aggregate-contributionstarget is correctly added aftergithub-update-users, ensuring users exist before their contributions are aggregated.backend/apps/github/Makefile (1)
24-27: LGTM!The new Makefile target follows the established pattern consistently with other targets in this file.
frontend/__tests__/mockData/mockUserDetails.ts (1)
16-22: LGTM!The mock
contributionDataprovides good test coverage with varied values including a zero-contribution day, which helps validate edge case handling in the heatmap component.frontend/__tests__/unit/components/ContributionHeatmap.test.tsx (3)
629-634: LGTM!Good test coverage for the new medium variant, verifying the expected height of 172px which fits logically between default (195px) and compact (150px).
661-668: LGTM!Consistent test coverage for the medium variant's container styling, following the same pattern as existing variant tests.
677-691: Test now uses medium variant for rerender scenario.The test verifies that title styling remains consistent across variants. Switching from
compacttomediumin the rerender case still validates the intended behavior (title classes unchanged between variants).backend/tests/apps/github/api/internal/nodes/user_test.py (1)
26-26: LGTM!The
contribution_datafield is correctly added to the expected field names set in alphabetical order, consistent with the existing test pattern.backend/apps/github/models/user.py (1)
57-62: LGTM!The
contribution_dataJSONField is correctly defined:
- Uses
default=dict(callable) to avoid the shared mutable default anti-patternblank=Truewithoutnull=Trueis the correct pattern for JSONField—empty dict is preferable to NULL- Clear help text documents the expected
date -> countmapping structurebackend/apps/github/migrations/0041_user_contribution_data.py (1)
1-22: LGTM!The migration correctly adds the
contribution_dataJSONField with options matching the model definition. This is an additive, backward-compatible change that won't affect existing data.frontend/__tests__/unit/pages/UserDetails.test.tsx (7)
8-8: LGTM!Good cleanup—only importing
fetchHeatmapDatasincedrawContributionsis no longer used directly in tests.
61-68: LGTM!The mock correctly provides a
data-testidfor reliable querying in tests, following the pattern used by other mocked components in this file.
81-87: LGTM!The mock return value now includes the
contributionsarray with the expected shape (date,count,intensity), aligning with the heatmap data structure.
297-299: LGTM!Switching from alt text querying to
data-testidis more reliable and decouples tests from accessibility attributes that might change.
303-321: LGTM!The test correctly verifies that when
contributionDataisnull, the heatmap component is not rendered. This properly tests the conditional rendering logic in the page component.
827-886: Good test coverage for contribution data edge cases.The new test suite covers the key scenarios:
- Heatmap renders when data exists
- Heatmap doesn't render with empty object
{}- Heatmap doesn't render with
nullThis ensures the page handles various backend states gracefully.
843-863: No changes needed. The test correctly verifies conditional rendering behavior.The conditional rendering check (
hasContributionData && ...) is correctly implemented in the page component at line 166. WhencontributionDatais{},hasContributionDataevaluates tofalse(sinceObject.keys({}).length > 0is false), preventing the entire<ContributionHeatmap>component from rendering. The mock is never invoked, so the test correctly passes when the heatmap is not in the DOM.backend/apps/github/api/internal/nodes/user.py (1)
16-16: JSONField requires explicit GraphQL type mapping in strawberry-django v0.73.0Adding
contribution_datato the fields list without an explicit scalar type will cause GraphQL serialization failures. Strawberry-django v0.73.0 does not automatically handle Django's JSONField—that support was added later in Strawberry core v0.99.0+.To fix this, you need to either:
- Import and use Strawberry's JSON scalar (
from strawberry.scalars import JSON) and define the field explicitly, or- Create a custom resolver that returns the JSONField as a Python dict/list
Likely an incorrect or invalid review comment.
frontend/src/components/ContributionHeatmap.tsx (1)
252-252: LGTM! Clean variant extension.The new
'medium'variant is appropriately added to the union type, maintaining type safety and allowing consumers to use the new size option.backend/tests/apps/github/models/user_test.py (1)
219-248: LGTM! Good coverage of the newcontribution_datafield.The tests appropriately verify:
- Default value is an empty dict
- JSON data can be stored and retrieved
- The field can be updated
These in-memory tests are suitable for unit testing the field definition. If integration tests exist elsewhere that verify actual database persistence, this coverage is complete.
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (4)
9-42: LGTM! Useful MockQuerySet utility.The
MockQuerySetclass provides a clean way to mock Django QuerySet behavior without database access. It supports the necessary methods (filter,exists,count,iterator,values,annotate) used by the command.
47-86: LGTM! Good test for empty contributions scenario.The test properly mocks
timezone.now()and verifies that 30 days of zero-filled data is returned when no contributions exist.
87-135: LGTM! Comprehensive test with contribution data.The test verifies correct aggregation across commits, PRs, and issues on different dates. The assertions clearly document expected behavior (e.g., Jan 1st = 2 commits + 1 PR = 3).
166-183: LGTM! Good negative test for user not found.The test properly verifies the error message is written when a specified user doesn't exist.
backend/apps/github/management/commands/github_aggregate_contributions.py
Outdated
Show resolved
Hide resolved
backend/apps/owasp/management/commands/owasp_aggregate_member_contributions.py
Show resolved
Hide resolved
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @backend/apps/github/management/commands/github_aggregate_contributions.py:
- Around line 117-141: The PR and Issue queries are grouping by the full
datetime; change both queries to use TruncDate("created_at") so aggregation
happens in the DB: in the PullRequest and Issue query blocks replace
.values("created_at").annotate(count=Count("id")) with
.annotate(date=TruncDate("created_at")).values("date").annotate(count=Count("id"))
(and update the loops to read pr["date"] / issue["date"] instead of
["created_at"]); also ensure TruncDate is imported from
django.db.models.functions if not already.
🧹 Nitpick comments (2)
backend/tests/apps/github/api/internal/nodes/user_test.py (1)
313-337: Tests don't exercise UserNode logic.These tests only verify that a Mock object returns the value assigned to it, which is tautological. Unlike other tests in this file (e.g.,
test_url_fieldcallsUserNode.url(mock_user)), these don't invoke any UserNode method.If
contribution_datais a simple passthrough field (auto-resolved by Strawberry from the model), explicit tests may be unnecessary. If there's a custom resolver, test it like other fields:result = UserNode.contribution_data(mock_user)Otherwise, consider removing these tests or clarifying their intent.
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (1)
31-41: Remove unusednoqadirectives.Per static analysis, the
ARG002rule is not enabled, making thesenoqacomments unnecessary.🔧 Proposed fix
- def iterator(self, chunk_size=None): # noqa: ARG002 + def iterator(self, chunk_size=None): """Mock iterator method.""" return iter(self._items) - def values(self, *_args): # noqa: ARG002 + def values(self, *_args): """Mock values method.""" return self
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/api/internal/nodes/user_test.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-12-18T05:39:42.678Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:40-40
Timestamp: 2025-12-18T05:39:42.678Z
Learning: In Django management commands, prefer using self.stdout.write(...) over print(...) for user-facing stdout output. This aligns with Django conventions and improves testability. When emitting messages, consider using self.stdout.write and, for styled messages, use self.style.SUCCESS/ERROR as appropriate to maintain consistent command output formatting. Apply this guideline to all Python files within any project's management/commands directory.
Applied to files:
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
📚 Learning: 2025-12-31T05:17:39.659Z
Learnt from: kart-u
Repo: OWASP/Nest PR: 3101
File: backend/apps/common/extensions.py:92-98
Timestamp: 2025-12-31T05:17:39.659Z
Learning: In this codebase, import OperationType for GraphQL operations from the graphql-core package rather than from strawberry. Use 'from graphql import OperationType'. Strawberry re-exports via graphql-core internally, so relying on strawberry's API may be brittle. Apply this rule to all Python files that deal with GraphQL operation types; ensure imports come from graphql (graphql-core) and not from strawberry packages. This improves compatibility and avoids coupling to strawberry's internals.
Applied to files:
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/tests/apps/github/api/internal/nodes/user_test.py
📚 Learning: 2026-01-01T17:48:23.963Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:41-47
Timestamp: 2026-01-01T17:48:23.963Z
Learning: In Django code, be aware that a QuerySet's boolean evaluation (e.g., if not queryset) runs a database query to determine emptiness. While it is technically valid to use the queryset in a boolean context, use queryset.exists() for existence checks to avoid unnecessary queries and improve performance. Applicable broadly to Python/Django files rather than just this specific path.
Applied to files:
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.pybackend/tests/apps/github/api/internal/nodes/user_test.py
📚 Learning: 2025-09-10T15:32:12.688Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 2211
File: backend/apps/nest/controllers/calendar_events.py:0-0
Timestamp: 2025-09-10T15:32:12.688Z
Learning: In the backend/apps/nest/controllers/calendar_events.py file, the scheduled_time parameter in the schedule_reminder function is guaranteed to be timezone-aware, so explicit timezone awareness validation is not needed.
Applied to files:
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
🧬 Code graph analysis (2)
backend/apps/github/management/commands/github_aggregate_contributions.py (2)
backend/apps/github/models/commit.py (1)
Commit(11-110)backend/apps/github/models/user.py (2)
User(28-223)issues(74-81)
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (1)
backend/apps/github/management/commands/github_aggregate_contributions.py (2)
_aggregate_user_contributions(83-143)handle(42-81)
🪛 Ruff (0.14.11)
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
31-31: Unused noqa directive (non-enabled: ARG002)
Remove unused noqa directive
(RUF100)
35-35: Unused noqa directive (non-enabled: ARG002)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (11)
backend/tests/apps/github/api/internal/nodes/user_test.py (1)
26-26: LGTM!The expected field set correctly includes the new
contribution_datafield, aligning with the model and GraphQL schema updates.backend/apps/github/management/commands/github_aggregate_contributions.py (3)
1-21: LGTM!Imports are appropriate. Using
django.utils.timezonefor timezone-aware datetime handling is correct, andTruncDate/Countare suitable for the aggregation queries.
22-40: LGTM!Command arguments are well-structured with sensible defaults and clear help text.
42-81: LGTM!Good use of
users.exists()for existence checks andusers.iterator(chunk_size=batch_size)for memory-efficient processing. Theupdate_fieldsparameter insave()is a good practice for performance.One minor note: Line 71's
if contribution_data:will beTrueas long as the dict has keys (even if all counts are 0). This should work correctly since_aggregate_user_contributionsinitializes all dates in the range.backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (7)
47-81: LGTM!Test correctly validates the empty contribution case with proper mocking of timezone and model queries.
83-127: Test mirrors current implementation inconsistency.The mock data for PRs and issues uses
created_at(datetime) while commits usedate. If you apply the suggested fix to useTruncDatefor PRs and issues in the command, update these mocks accordingly:mock_pr.objects.filter.return_value = MockQuerySet( - [{"created_at": datetime(2024, 1, 1, 11, 0, tzinfo=UTC), "count": 1}] + [{"date": datetime(2024, 1, 1, tzinfo=UTC).date(), "count": 1}] ) mock_issue.objects.filter.return_value = MockQuerySet( - [{"created_at": datetime(2024, 1, 3, 12, 0, tzinfo=UTC), "count": 3}] + [{"date": datetime(2024, 1, 3, tzinfo=UTC).date(), "count": 3}] )
129-156: LGTM!Test properly validates the handle flow for a specific user, including verification that
save()is called with the correctupdate_fields.
158-174: LGTM!Good negative test case that verifies proper error messaging when a user is not found.
176-209: LGTM!Test validates batch processing of multiple users correctly.
211-243: LGTM!Test properly validates the custom days parameter affects the start date calculation.
245-277: LGTM!Test validates the date format contract for contribution data keys.
backend/apps/owasp/management/commands/owasp_aggregate_member_contributions.py
Show resolved
Hide resolved
f4302b9 to
cc0637b
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@backend/tests/apps/github/api/internal/nodes/user_test.py`:
- Around line 313-337: The two tests (test_contribution_data_field and
test_contribution_data_field_empty) only set and read attributes on a Mock and
do not call any UserNode logic; either update them to exercise the actual
resolver (e.g., call UserNode.contribution_data(user) or the appropriate
resolver method on UserNode) and assert its returned value based on a mock User
instance, or remove these tests if contribution_data is just a direct field and
already covered by test_meta_configuration; locate the tests by their names and
the UserNode class/resolver to implement the change.
🧹 Nitpick comments (1)
backend/apps/github/management/commands/github_aggregate_contributions.py (1)
83-145: LGTM with optional DRY suggestion.The aggregation logic is correct. All three queries (Commits, PRs, Issues) properly use
TruncDatefor database-level date grouping.♻️ Optional: Extract repeated query pattern into helper
The three query blocks share identical structure. If you want to reduce duplication:
def _aggregate_user_contributions(self, user: User, start_date: datetime) -> dict[str, int]: contribution_data = {} current_date = start_date.date() end_date = timezone.now().date() while current_date <= end_date: date_str = current_date.strftime("%Y-%m-%d") contribution_data[date_str] = 0 current_date += timedelta(days=1) models = [Commit, PullRequest, Issue] for model in models: queryset = ( model.objects.filter(author=user, created_at__gte=start_date) .annotate(date=TruncDate("created_at")) .values("date") .annotate(count=Count("id")) ) for entry in queryset: date_str = entry["date"].strftime("%Y-%m-%d") contribution_data[date_str] = contribution_data.get(date_str, 0) + entry["count"] return contribution_data
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/api/internal/nodes/user_test.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-12-31T05:17:39.659Z
Learnt from: kart-u
Repo: OWASP/Nest PR: 3101
File: backend/apps/common/extensions.py:92-98
Timestamp: 2025-12-31T05:17:39.659Z
Learning: In this codebase, import OperationType for GraphQL operations from the graphql-core package rather than from strawberry. Use 'from graphql import OperationType'. Strawberry re-exports via graphql-core internally, so relying on strawberry's API may be brittle. Apply this rule to all Python files that deal with GraphQL operation types; ensure imports come from graphql (graphql-core) and not from strawberry packages. This improves compatibility and avoids coupling to strawberry's internals.
Applied to files:
backend/tests/apps/github/api/internal/nodes/user_test.pybackend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
📚 Learning: 2026-01-01T17:48:23.963Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:41-47
Timestamp: 2026-01-01T17:48:23.963Z
Learning: In Django code, be aware that a QuerySet's boolean evaluation (e.g., if not queryset) runs a database query to determine emptiness. While it is technically valid to use the queryset in a boolean context, use queryset.exists() for existence checks to avoid unnecessary queries and improve performance. Applicable broadly to Python/Django files rather than just this specific path.
Applied to files:
backend/tests/apps/github/api/internal/nodes/user_test.pybackend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
📚 Learning: 2025-12-18T05:39:42.678Z
Learnt from: rudransh-shrivastava
Repo: OWASP/Nest PR: 2948
File: backend/apps/owasp/management/commands/owasp_generate_community_snapshot_video.py:40-40
Timestamp: 2025-12-18T05:39:42.678Z
Learning: In Django management commands, prefer using self.stdout.write(...) over print(...) for user-facing stdout output. This aligns with Django conventions and improves testability. When emitting messages, consider using self.stdout.write and, for styled messages, use self.style.SUCCESS/ERROR as appropriate to maintain consistent command output formatting. Apply this guideline to all Python files within any project's management/commands directory.
Applied to files:
backend/apps/github/management/commands/github_aggregate_contributions.pybackend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
📚 Learning: 2025-09-10T15:32:12.688Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 2211
File: backend/apps/nest/controllers/calendar_events.py:0-0
Timestamp: 2025-09-10T15:32:12.688Z
Learning: In the backend/apps/nest/controllers/calendar_events.py file, the scheduled_time parameter in the schedule_reminder function is guaranteed to be timezone-aware, so explicit timezone awareness validation is not needed.
Applied to files:
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py
🧬 Code graph analysis (2)
backend/apps/github/management/commands/github_aggregate_contributions.py (2)
backend/apps/github/models/commit.py (1)
Commit(11-110)backend/apps/github/models/user.py (2)
User(28-223)issues(74-81)
backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (1)
backend/apps/github/management/commands/github_aggregate_contributions.py (2)
_aggregate_user_contributions(83-145)handle(42-81)
🔇 Additional comments (13)
backend/tests/apps/github/api/internal/nodes/user_test.py (1)
26-26: LGTM!The addition of
contribution_datato the expected field names correctly validates the new GraphQL field exposure in UserNode.backend/apps/github/management/commands/github_aggregate_contributions.py (3)
1-15: LGTM!Imports are well-organized and appropriate. Using
TruncDatefromdjango.db.models.functionsaligns with best practices for date aggregation at the database level.
22-40: LGTM!Command arguments are well-defined with appropriate defaults and help text.
42-81: LGTM!The handle method follows Django conventions well:
- Uses
self.stdout.writewith styled output- Uses
users.exists()for existence check (efficient)- Memory-efficient iteration with
iterator(chunk_size=batch_size)- Targeted save with
update_fields=["contribution_data"]backend/tests/apps/github/management/commands/github_aggregate_contributions_test.py (9)
1-7: LGTM!Imports are appropriate for the test module.
9-42: LGTM!The MockQuerySet is a clean utility for testing without database access. It properly supports the chaining pattern used by the command.
47-81: LGTM!Test correctly validates zero-filled date range when there are no contributions.
83-127: LGTM!Test correctly validates aggregation logic across commits, PRs, and issues with proper date summing.
129-156: LGTM!Test correctly validates the handle method with a found user, including verification of save behavior.
158-174: LGTM!Test correctly validates the error path when a specified user is not found.
176-209: LGTM!Test correctly validates bulk processing of multiple users.
211-243: LGTM!Test correctly validates custom days parameter handling with appropriate datetime comparison tolerance.
245-277: LGTM!Test correctly validates the YYYY-MM-DD date format for contribution data keys.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@docker-compose/local/compose.yaml`:
- Line 70: Revert the PR-specific Docker volume name introduced in compose.yaml:
replace any occurrences of the volume identifier "db-data-pr-3298" back to the
canonical "db-data" used on main (this appears in the service bind for Postgres
and the volumes section); ensure both the service volume mount and the volumes
declaration (symbols: the Postgres service volume mapping and the volumes entry
that defines db-data-pr-3298) are updated so the repo uses "db-data" again
before merging.
arkid15r
left a comment
There was a problem hiding this comment.
It doesn't seem you ran the tests locally 🤷♂️
e2e-nest-data-loader | Loading data from dump...
e2e-nest-db | 2026-01-28 01:22:12.548 UTC [116] ERROR: null value in column "contribution_data" of relation "github_users" violates not-null constraint
e2e-nest-db | 2026-01-28 01:22:12.548 UTC [116] DETAIL: Failing row contains (1908, 2024-09-12 00:30:14.55+00, 2025-03-20 12:58:16.628+00, , Dhanxy, , https://avatars.githubusercontent.com/u/107783562?v=4, , , 0, 1, 0, 0, 0, , f, , U_kgDOBmylig, 2022-06-19 04:40:23+00, 2023-11-29 20:07:09+00, f, 0, f, t, null).
e2e-nest-db | 2026-01-28 01:22:12.548 UTC [116] CONTEXT: COPY github_users, line 1: "1908 2024-09-12 00:30:14.55+00 2025-03-20 12:58:16.628+00 Dhanxy https://avatars.githubusercontent..."
e2e-nest-db | 2026-01-28 01:22:12.548 UTC [116] STATEMENT: COPY public.github_users (id, nest_created_at, nest_updated_at, name, login, email, avatar_url, company, location, collaborators_count, following_count, followers_count, public_gists_count, public_repositories_count, bio, is_hireable, twitter_username, node_id, created_at, updated_at, is_bot, contributions_count, is_owasp_staff, has_public_member_page) FROM stdin;
I'm merging this PR after applying multiple fixes.
|
|
||
| if contribution_data: | ||
| user.contribution_data = contribution_data | ||
| user.save(update_fields=["contribution_data"]) |
There was a problem hiding this comment.
I indicated this case for you in previous similar PR review but it doesn't seem you learned from it. In general it's not a good sign from mentor's perspective.
Aggregating OWASP community member contributions
Aggregating contributions since 2025-01-28 (365 days back)
Processing 6965 users...
Processed 100/6965 users...
^Cmake: *** [owasp-aggregate-member-contributions] Interrupt: 2
make owasp-aggregate-member-contributions 0.02s user 0.03s system 0% cpu 4:43.55 total
Aggregating OWASP community member contributions
Aggregating contributions since 2025-01-28 (365 days back)
Processing 6965 users...
Successfully aggregated contributions for 6965 members
make owasp-aggregate-member-contributions 0.03s user 0.04s system 0% cpu 30.167 total
There was a problem hiding this comment.
Sorry for missing this, I understand the concern and will make sure to be more careful about this in future PRs.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/__tests__/a11y/pages/UserDetails.a11y.test.tsx (1)
42-45: Remove the unusedgithubHeatmapmock.The
fetchHeatmapDataanddrawContributionsfunctions are not used anywhere in the codebase. Since theContributionHeatmapcomponent is already mocked, these utility mocks serve no purpose. Remove lines 42-45.
🧹 Nitpick comments (4)
backend/apps/github/migrations/0043_alter_user_contribution_data.py (1)
15-21: Consider the semantics ofnull=Truewithdefault=dict.Having both
null=Trueanddefault=dictallows the field to be eitherNoneor{}. If this is intentional (e.g.,None= "not yet computed",{}= "computed but no contributions"), this is fine. Otherwise, you could simplify by removingnull=Trueto ensure the field always contains a dict.backend/tests/apps/owasp/management/commands/owasp_aggregate_entity_contributions_test.py (1)
53-56: Consider renaming the test class for clarity.The test class
TestOwaspAggregateContributionscould be renamed toTestOwaspAggregateEntityContributionsto better reflect the command being tested and distinguish it from the member contributions tests.Suggested change
-class TestOwaspAggregateContributions: +class TestOwaspAggregateEntityContributions:frontend/__tests__/unit/pages/UserDetails.test.tsx (1)
281-301: Remove the redundant null-contribution test.
This test now overlaps with the later “Contribution Heatmap” block that also coverscontributionData: null. Keeping one will reduce test duplication.🧹 Suggested cleanup
-test('handles contribution heatmap loading error correctly', async () => { - const dataWithoutContributions = { - ...mockUserDetailsData, - user: { - ...mockUserDetailsData.user, - contributionData: null, - }, - } - - ;(useQuery as unknown as jest.Mock).mockReturnValue({ - data: dataWithoutContributions, - error: null, - loading: false, - }) - - render(<UserDetailsPage />) - - await waitFor(() => { - const heatmap = screen.queryByTestId('contribution-heatmap') - expect(heatmap).not.toBeInTheDocument() - }) -})backend/apps/owasp/management/commands/owasp_aggregate_member_contributions.py.bak (1)
1-142: Consider removing the.bakcommand file.
It duplicates the active command and can easily drift or confuse future edits. Keeping only the real command file is cleaner.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3298 +/- ##
==========================================
+ Coverage 85.49% 85.55% +0.06%
==========================================
Files 462 463 +1
Lines 14260 14306 +46
Branches 1900 1905 +5
==========================================
+ Hits 12191 12240 +49
+ Misses 1689 1687 -2
+ Partials 380 379 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
0a83697
|



Proposed change
This PR refactors the member profile page to reuse the existing ContributionHeatmap component for improved design consistency and code reuse across the platform.
Resolves #2705
Checklist
make check-testlocally: all warnings addressed, tests passed