-
-
Notifications
You must be signed in to change notification settings - Fork 286
UI/ux issue page #2397
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
UI/ux issue page #2397
Conversation
* fix ui bugs * update format * fix test cases * fix test cases * update UI * update UI * update line clamp property * fix test case * Update styling --------- Co-authored-by: Kate Golovanova <[email protected]> Co-authored-by: Arkadii Yakovets <[email protected]>
* Update docker-compose/local.yaml * UI/ux mentorship program update (OWASP#2244) * fix ui bugs * update format * fix test cases * fix test cases * update UI * update UI * update line clamp property * fix test case * Update styling --------- Co-authored-by: Kate Golovanova <[email protected]> Co-authored-by: Arkadii Yakovets <[email protected]> * fix params and remove refresh params * update direct cache * fix test cases * better exception caching * update logic Update docker-compose/local.yaml UI/ux mentorship program update (OWASP#2244) * fix ui bugs * update format * fix test cases * fix test cases * update UI * update UI * update line clamp property * fix test case * Update styling --------- Co-authored-by: Kate Golovanova <[email protected]> Co-authored-by: Arkadii Yakovets <[email protected]> * Update apollo cache logic on updating programs and modules * restore files * fix test cases * fix test cases * update button to link * fix type --------- Co-authored-by: Arkadii Yakovets <[email protected]> Co-authored-by: Kate Golovanova <[email protected]> Co-authored-by: Arkadii Yakovets <[email protected]>
Summary by CodeRabbit
WalkthroughAdds mentorship issues management: backend models/migrations for Issue comments, Issue.level, PullRequest.related_issues; admin configs; sync/management commands; GraphQL nodes/mutations for issues, assignees, interests; Makefile targets. Frontend adds issues list/detail pages, queries/mutations, UI tweaks, and test updates. Docker Compose volume names changed; dotenv loaded in manage.py. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/SingleModuleCard.tsx (1)
70-85: Link construction must not referencewindowat render timeRendering this component on the server will throw because
windowdoesn’t exist there. Switch to a relative href or derive the base path viausePathname()so the module page remains navigable in SSR.Apply this diff:
- <Link - href={`${window.location.pathname}/modules/${module.key}`} + <Link + href={`./modules/${module.key}`}
🧹 Nitpick comments (4)
backend/apps/mentorship/admin/task.py (1)
28-29: Consider explicit NULL ordering for better UX.The descending sort by
assigned_atis a good default. However, sinceassigned_atis nullable (per the model changes in this PR), database-specific NULL ordering behavior may affect the list view. In PostgreSQL,ORDER BY field DESCdefaults toNULLS FIRST, meaning tasks withNULL assigned_at(unassigned or pending tasks) will appear at the top of the list, potentially obscuring recently assigned tasks.If you want recently assigned tasks to appear first and NULL values last, consider using Django's
Fexpressions:from django.db.models import F ordering = [F("assigned_at").desc(nulls_last=True)]This ensures a consistent and predictable order regardless of the database backend.
frontend/__tests__/unit/components/SingleModuleCard.test.tsx (1)
165-171: Update expectation to match valid hrefOnce the component stops using
window, the link should render as./modules/test-module(no double slash). Please align the assertion so the test reflects the corrected href.frontend/src/components/ProgramCard.tsx (1)
17-22: Consider reusing the existing date formatter utility.A
formatDateutility already exists atfrontend/src/utils/dateFormatter.tsthat handles both Unix timestamps and ISO strings. The local implementation duplicates this logic.Apply this diff to use the shared utility:
+import { formatDate } from 'utils/dateFormatter' import { faEye } from '@fortawesome/free-regular-svg-icons' import { faEdit } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Tooltip } from '@heroui/tooltip' import type React from 'react' import { Program } from 'types/mentorship' import ActionButton from 'components/ActionButton' interface ProgramCardProps { program: Program onEdit?: (key: string) => void onView: (key: string) => void accessLevel: 'admin' | 'user' } const ProgramCard: React.FC<ProgramCardProps> = ({ program, onEdit, onView, accessLevel }) => { - const formatDate = (d: string) => - new Date(d).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric', - }) - const roleClass = {backend/apps/github/api/internal/nodes/issue.py (1)
55-58: Consider optimizing the database query.The resolver may trigger N+1 queries since it doesn't use
select_related("user"). For better performance, especially when resolving multiple issues, consider applying query optimization.Apply this diff to optimize the query:
@strawberry.field def interested_users(self) -> list[UserNode]: """Return all users who have expressed interest in this issue.""" - return [interest.user for interest in IssueUserInterest.objects.filter(issue=self)] + interests = IssueUserInterest.objects.filter(issue=self).select_related("user") + return [interest.user for interest in interests]
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
frontend/src/types/__generated__/moduleMutations.generated.tsis excluded by!**/__generated__/**frontend/src/types/__generated__/programsMutations.generated.tsis excluded by!**/__generated__/**
📒 Files selected for processing (64)
backend/Makefile(1 hunks)backend/apps/github/Makefile(1 hunks)backend/apps/github/admin/__init__.py(1 hunks)backend/apps/github/admin/comment.py(1 hunks)backend/apps/github/admin/issue.py(1 hunks)backend/apps/github/admin/pull_request.py(1 hunks)backend/apps/github/api/internal/nodes/issue.py(2 hunks)backend/apps/github/common.py(2 hunks)backend/apps/github/management/commands/github_update_pull_requests.py(1 hunks)backend/apps/github/migrations/0037_issue_level_comment.py(1 hunks)backend/apps/github/migrations/0038_pullrequest_related_issues.py(1 hunks)backend/apps/github/models/__init__.py(1 hunks)backend/apps/github/models/comment.py(1 hunks)backend/apps/github/models/issue.py(3 hunks)backend/apps/github/models/pull_request.py(1 hunks)backend/apps/mentorship/Makefile(1 hunks)backend/apps/mentorship/admin/__init__.py(1 hunks)backend/apps/mentorship/admin/issue_user_interest.py(1 hunks)backend/apps/mentorship/admin/module.py(1 hunks)backend/apps/mentorship/admin/task.py(1 hunks)backend/apps/mentorship/api/internal/mutations/module.py(3 hunks)backend/apps/mentorship/api/internal/nodes/module.py(2 hunks)backend/apps/mentorship/management/commands/mentorship_update_comments.py(1 hunks)backend/apps/mentorship/management/commands/sync_issue_levels.py(1 hunks)backend/apps/mentorship/management/commands/sync_module_issues.py(1 hunks)backend/apps/mentorship/migrations/0005_remove_task_level_module_issues_and_more.py(1 hunks)backend/apps/mentorship/models/__init__.py(1 hunks)backend/apps/mentorship/models/issue_user_interest.py(1 hunks)backend/apps/mentorship/models/managers/__init__.py(1 hunks)backend/apps/mentorship/models/managers/module.py(1 hunks)backend/apps/mentorship/models/module.py(2 hunks)backend/apps/mentorship/models/task.py(1 hunks)backend/apps/mentorship/utils.py(1 hunks)backend/manage.py(1 hunks)docker-compose/local.yaml(5 hunks)frontend/__tests__/unit/components/ProgramCard.test.tsx(2 hunks)frontend/__tests__/unit/components/SingleModuleCard.test.tsx(4 hunks)frontend/__tests__/unit/pages/CreateModule.test.tsx(1 hunks)frontend/__tests__/unit/pages/EditModule.test.tsx(1 hunks)frontend/__tests__/unit/pages/ProgramDetails.test.tsx(1 hunks)frontend/__tests__/unit/pages/ProgramDetailsMentorship.test.tsx(1 hunks)frontend/src/app/mentorship/programs/[programKey]/modules/[moduleKey]/page.tsx(2 hunks)frontend/src/app/mentorship/programs/[programKey]/page.tsx(2 hunks)frontend/src/app/mentorship/programs/page.tsx(1 hunks)frontend/src/app/my/mentorship/page.tsx(1 hunks)frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx(1 hunks)frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/edit/page.tsx(1 hunks)frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx(1 hunks)frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/page.tsx(1 hunks)frontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsx(3 hunks)frontend/src/app/my/mentorship/programs/[programKey]/page.tsx(4 hunks)frontend/src/components/ActionButton.tsx(1 hunks)frontend/src/components/CardDetailsPage.tsx(1 hunks)frontend/src/components/ModuleCard.tsx(2 hunks)frontend/src/components/ModuleForm.tsx(1 hunks)frontend/src/components/ProgramCard.tsx(3 hunks)frontend/src/components/ProgramForm.tsx(1 hunks)frontend/src/components/SingleModuleCard.tsx(1 hunks)frontend/src/server/mutations/moduleMutations.ts(2 hunks)frontend/src/server/mutations/programsMutations.ts(3 hunks)frontend/src/server/queries/issueQueries.ts(1 hunks)frontend/src/server/queries/moduleQueries.ts(1 hunks)frontend/src/types/issue.ts(2 hunks)frontend/src/types/pullRequest.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
PR: OWASP/Nest#2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.
Applied to files:
frontend/src/components/ActionButton.tsx
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS is actively used in frontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsx for program editing functionality and cannot be removed. It serves a different purpose than GET_PROGRAM_ADMIN_DETAILS, providing comprehensive program information needed for editing.
Applied to files:
frontend/src/app/mentorship/programs/[programKey]/page.tsxfrontend/src/app/my/mentorship/programs/[programKey]/edit/page.tsxfrontend/src/app/my/mentorship/programs/[programKey]/page.tsxfrontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsxfrontend/src/server/mutations/programsMutations.ts
📚 Learning: 2025-09-29T06:02:35.566Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2178
File: frontend/src/components/SingleModuleCard.tsx:54-54
Timestamp: 2025-09-29T06:02:35.566Z
Learning: In the Module type from types/mentorship.ts, the experienceLevel field is required (experienceLevel: ExperienceLevelEnum), not optional, so null/undefined checks are not needed when accessing this field.
Applied to files:
frontend/src/app/mentorship/programs/[programKey]/modules/[moduleKey]/page.tsx
📚 Learning: 2025-07-13T07:31:06.511Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: frontend/src/components/ModuleCard.tsx:53-55
Timestamp: 2025-07-13T07:31:06.511Z
Learning: In Next.js 13+ app router, useRouter from 'next/navigation' does not provide asPath or query properties. Use useParams to extract route parameters and usePathname to get the current pathname instead.
Applied to files:
frontend/src/app/my/mentorship/programs/[programKey]/page.tsxfrontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsx
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details. These queries cannot be removed or merged as they serve different use cases in the application.
Applied to files:
frontend/src/server/mutations/programsMutations.ts
📚 Learning: 2025-08-31T13:47:15.861Z
Learnt from: rudransh-shrivastava
PR: OWASP/Nest#2155
File: frontend/src/server/queries/programsQueries.ts:81-81
Timestamp: 2025-08-31T13:47:15.861Z
Learning: In frontend/src/server/queries/programsQueries.ts, GET_PROGRAM_DETAILS and GET_PROGRAM_ADMIN_DETAILS are two separate queries serving different purposes: GET_PROGRAM_DETAILS fetches comprehensive program information while GET_PROGRAM_ADMIN_DETAILS fetches only admin-related details.
Applied to files:
frontend/src/server/mutations/programsMutations.ts
🧬 Code graph analysis (33)
backend/apps/mentorship/models/managers/__init__.py (1)
backend/apps/mentorship/models/managers/module.py (1)
PublishedModuleManager(8-13)
backend/apps/mentorship/admin/__init__.py (1)
backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)
frontend/src/app/mentorship/programs/[programKey]/page.tsx (1)
frontend/src/utils/capitalize.ts (1)
titleCaseWord(1-4)
frontend/src/app/mentorship/programs/[programKey]/modules/[moduleKey]/page.tsx (1)
frontend/src/utils/capitalize.ts (1)
titleCaseWord(1-4)
backend/apps/mentorship/models/issue_user_interest.py (3)
backend/apps/github/models/issue.py (1)
Meta(24-30)backend/apps/github/api/internal/queries/user.py (1)
user(40-53)backend/apps/mentorship/api/internal/nodes/mentor.py (2)
login(23-25)name(18-20)
backend/apps/mentorship/api/internal/mutations/module.py (5)
backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)backend/apps/nest/api/internal/permissions.py (1)
IsAuthenticated(10-21)backend/apps/mentorship/api/internal/nodes/module.py (2)
ModuleNode(17-94)issues(43-49)backend/apps/mentorship/models/module.py (1)
Module(17-104)backend/apps/mentorship/models/mentor.py (1)
Mentor(11-40)
backend/apps/mentorship/admin/issue_user_interest.py (1)
backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)
backend/apps/github/admin/comment.py (1)
backend/apps/github/models/comment.py (1)
Comment(11-81)
backend/apps/mentorship/api/internal/nodes/module.py (3)
backend/apps/github/api/internal/nodes/issue.py (2)
IssueNode(23-63)interested_users(56-58)backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)backend/apps/mentorship/models/task.py (1)
Task(10-80)
backend/apps/github/management/commands/github_update_pull_requests.py (1)
backend/apps/github/models/pull_request.py (2)
PullRequest(11-152)bulk_save(114-116)
backend/apps/mentorship/models/module.py (2)
backend/apps/mentorship/models/managers/module.py (1)
PublishedModuleManager(8-13)backend/apps/mentorship/api/internal/nodes/module.py (1)
issues(43-49)
frontend/__tests__/unit/components/SingleModuleCard.test.tsx (1)
frontend/src/wrappers/testUtil.tsx (1)
render(14-14)
backend/apps/mentorship/management/commands/sync_module_issues.py (4)
backend/apps/github/models/issue.py (2)
Issue(18-233)save(186-195)backend/apps/mentorship/models/task.py (2)
Task(10-80)Status(19-25)backend/apps/mentorship/utils.py (1)
normalize_name(4-6)backend/apps/github/models/repository.py (1)
path(154-156)
frontend/src/types/issue.ts (1)
frontend/src/types/pullRequest.ts (1)
PullRequest(3-11)
backend/apps/mentorship/utils.py (1)
backend/apps/mentorship/api/internal/nodes/mentor.py (1)
name(18-20)
backend/apps/mentorship/management/commands/sync_issue_levels.py (4)
backend/apps/github/models/issue.py (1)
Issue(18-233)backend/apps/github/models/label.py (1)
Label(9-77)backend/apps/mentorship/models/task_level.py (1)
TaskLevel(8-61)backend/apps/mentorship/utils.py (1)
normalize_name(4-6)
frontend/src/components/ProgramCard.tsx (1)
frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
frontend/src/app/my/mentorship/programs/[programKey]/page.tsx (5)
frontend/src/types/mentorship.ts (2)
Program(22-37)Module(52-64)frontend/src/server/mutations/programsMutations.ts (1)
UPDATE_PROGRAM_STATUS_MUTATION(49-57)frontend/src/server/queries/programsQueries.ts (1)
GET_PROGRAM_AND_MODULES(44-81)frontend/src/utils/capitalize.ts (1)
titleCaseWord(1-4)frontend/src/utils/dateFormatter.ts (1)
formatDate(1-20)
backend/apps/mentorship/models/__init__.py (1)
backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)
backend/apps/mentorship/migrations/0005_remove_task_level_module_issues_and_more.py (1)
backend/apps/github/migrations/0037_issue_level_comment.py (1)
Migration(7-74)
backend/apps/github/admin/__init__.py (1)
backend/apps/github/admin/comment.py (1)
CommentAdmin(8-18)
backend/apps/github/models/__init__.py (2)
backend/apps/github/models/comment.py (1)
Comment(11-81)backend/apps/github/models/issue.py (1)
Issue(18-233)
frontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsx (3)
frontend/src/server/queries/programsQueries.ts (1)
GET_PROGRAM_AND_MODULES(44-81)frontend/src/types/mentorship.ts (1)
Module(52-64)frontend/src/app/global-error.tsx (1)
handleAppError(66-86)
frontend/src/components/ModuleCard.tsx (1)
frontend/src/components/TruncatedText.tsx (1)
TruncatedText(3-45)
backend/apps/mentorship/models/managers/module.py (1)
backend/apps/mentorship/models/program.py (1)
ProgramStatus(25-28)
backend/apps/github/api/internal/nodes/issue.py (4)
backend/apps/github/api/internal/nodes/pull_request.py (1)
PullRequestNode(17-42)frontend/src/types/issue.ts (1)
Issue(4-21)backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)backend/apps/mentorship/api/internal/nodes/module.py (1)
interested_users(62-72)
frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/page.tsx (5)
frontend/src/server/queries/moduleQueries.ts (1)
GET_MODULE_ISSUES(79-120)frontend/src/app/global-error.tsx (2)
handleAppError(66-86)ErrorDisplay(28-51)backend/apps/mentorship/api/internal/nodes/module.py (1)
issues(43-49)backend/apps/github/api/internal/nodes/issue.py (2)
labels(51-53)assignees(46-48)frontend/src/components/TruncatedText.tsx (1)
TruncatedText(3-45)
backend/apps/github/migrations/0037_issue_level_comment.py (1)
backend/apps/mentorship/migrations/0005_remove_task_level_module_issues_and_more.py (1)
Migration(7-79)
backend/apps/github/common.py (5)
backend/apps/github/models/comment.py (3)
Comment(11-81)update_data(59-81)bulk_save(54-56)backend/apps/github/models/issue.py (4)
Issue(18-233)update_data(209-233)save(186-195)bulk_save(198-200)backend/apps/github/models/repository.py (2)
path(154-156)update_data(307-349)backend/apps/github/models/user.py (3)
User(19-159)update_data(130-159)bulk_save(110-112)backend/apps/common/models.py (1)
bulk_save(19-34)
backend/apps/github/models/comment.py (3)
backend/apps/common/models.py (2)
BulkSaveModel(10-34)TimestampedModel(37-46)backend/apps/common/utils.py (1)
truncate(181-193)backend/apps/github/models/issue.py (5)
Meta(24-30)from_github(107-146)bulk_save(198-200)update_data(209-233)save(186-195)
backend/apps/github/models/issue.py (1)
backend/apps/github/models/generic_issue_model.py (1)
GenericIssueModel(10-77)
backend/apps/mentorship/management/commands/mentorship_update_comments.py (5)
backend/apps/common/utils.py (1)
truncate(181-193)backend/apps/github/common.py (1)
sync_issue_comments(237-292)backend/apps/github/models/issue.py (1)
Issue(18-233)backend/apps/mentorship/models/issue_user_interest.py (1)
IssueUserInterest(6-31)backend/apps/mentorship/models/module.py (1)
Module(17-104)
frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/issues/[issueId]/page.tsx (3)
frontend/src/server/queries/issueQueries.ts (3)
GET_MODULE_ISSUE_VIEW(3-53)ASSIGN_ISSUE_TO_USER(55-71)UNASSIGN_ISSUE_FROM_USER(73-89)frontend/src/app/global-error.tsx (1)
ErrorDisplay(28-51)frontend/src/components/TruncatedText.tsx (1)
TruncatedText(3-45)
🪛 checkmake (0.2.2)
backend/apps/mentorship/Makefile
[warning] 1-1: Missing required phony target "all"
(minphony)
[warning] 1-1: Missing required phony target "clean"
(minphony)
[warning] 1-1: Missing required phony target "test"
(minphony)
🔇 Additional comments (36)
backend/manage.py (1)
14-14: LGTM!Loading dotenv inside the main guard is the correct approach for Django's manage.py.
frontend/src/app/my/mentorship/programs/[programKey]/modules/[moduleKey]/edit/page.tsx (1)
120-120: LGTM! Verify parent page refresh behavior.The navigation change is consistent with the test updates and correctly uses the
programKeyparameter. Ensure the parent program page properly refreshes its data when navigated to after module updates.frontend/__tests__/unit/pages/EditModule.test.tsx (1)
117-117: LGTM! Consistent with implementation changes.The test expectation correctly reflects the implementation change in the module edit page.
frontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsx (2)
8-8: LGTM!The new imports support the cache update functionality added to the mutation.
Also applies to: 10-10, 12-12
132-132: Verify navigation behavior if cache update fails.The removal of the
?refreshquery parameter is appropriate when cache updates work correctly. However, if the cache update fails (see previous comment), the user won't see the new module on the destination page.Test this scenario:
- Create a module when the
GET_PROGRAM_AND_MODULESquery hasn't been executed yet (cache is empty)- Verify that the new module appears on the program page after navigation
- If it doesn't appear, consider keeping a lightweight refresh mechanism as a fallback
frontend/src/components/ProgramCard.tsx (2)
30-30: LGTM: Clean fallback and consistent line-clamping.The description handling with a simple fallback and consistent
line-clamp-6styling provides a stable layout regardless of content length.Also applies to: 65-69
33-35: LGTM: Responsive sizing and improved layout structure.The responsive card sizing and restructured flex containers provide better visual hierarchy and separation between content and actions.
Also applies to: 72-72
frontend/__tests__/unit/components/ProgramCard.test.tsx (2)
27-33: LGTM: Simple and effective Tooltip mock.The mock implementation correctly wraps children and provides the title attribute for testing, which is sufficient for unit testing the Tooltip integration.
201-211: LGTM: Correct verification of line-clamp styling.The test properly verifies that short descriptions render with the
line-clamp-6class, ensuring consistent styling across all description lengths.backend/apps/mentorship/admin/module.py (1)
16-16: LGTM!The autocomplete configuration for the issues field follows Django admin best practices and will improve UX when linking issues to modules.
frontend/src/app/my/mentorship/page.tsx (1)
132-132: LGTM!The grid layout simplification improves consistency by using a unified gap and removes the 4-column breakpoint, creating a more predictable responsive behavior across viewport sizes.
backend/apps/mentorship/models/managers/module.py (1)
8-13: LGTM!The
PublishedModuleManagercorrectly implements a custom Django manager to filter modules by published program status. The implementation follows Django manager patterns and uses proper field lookups.backend/apps/github/api/internal/nodes/issue.py (4)
16-18: LGTM!The addition of
numberandsummaryfields to the GraphQL node exposes useful issue metadata to clients.
45-48: LGTM!The assignees resolver correctly returns a list of UserNode instances from the ManyToMany relationship.
50-53: LGTM!The labels resolver efficiently extracts label names using
values_listwithflat=True.
60-63: LGTM!The pull_requests resolver correctly uses
select_relatedto optimize the query and avoid N+1 issues when fetching related author and repository data.backend/apps/mentorship/admin/__init__.py (1)
3-3: LGTM!The import correctly exposes the
IssueUserInterestadmin, following the established pattern for admin module exposure in this package.backend/Makefile (1)
3-3: LGTM!The inclusion of the mentorship Makefile follows the established pattern and enables mentorship-specific make targets at the top level.
frontend/src/types/pullRequest.ts (1)
4-4: LGTM!Adding the
idfield as a required string property is essential for stable cross-referencing with issues and enables proper PR tracking in UI components.frontend/src/server/mutations/moduleMutations.ts (1)
17-17: LGTM!Adding the
idfield to the mentors selection in both mutations is necessary for proper mentor identification and tracking when creating or updating modules. The change is applied consistently across bothUPDATE_MODULEandCREATE_MODULEoperations.Also applies to: 40-40
frontend/__tests__/unit/pages/ProgramDetails.test.tsx (1)
70-70: LGTM!Test expectation correctly updated to match the title-cased proficiency levels now rendered in the UI.
frontend/__tests__/unit/pages/ProgramDetailsMentorship.test.tsx (1)
70-70: LGTM!Test expectation correctly updated to match the title-cased proficiency levels now rendered in the UI.
backend/apps/github/admin/comment.py (1)
8-21: LGTM!The admin configuration correctly exposes Comment model fields for list display, filtering, and search. The use of
nest_created_atandnest_updated_atfields (inherited fromTimestampedModel) and the search pathauthor__loginare appropriate.backend/apps/github/models/__init__.py (1)
3-4: LGTM!The public API expansion to include
CommentandIssuefollows the existing export pattern and aligns with the new models introduced in this PR.backend/apps/mentorship/models/managers/__init__.py (1)
1-1: LGTM!The re-export of
PublishedModuleManagerfollows standard package organization patterns and makes the manager accessible at the package level.backend/apps/github/admin/issue.py (1)
22-22: LGTM!Adding
levelto the list display provides useful visibility for issue categorization in the admin interface. The field is properly defined on the Issue model via the recent migration.backend/apps/github/admin/pull_request.py (1)
17-17: LGTM!Adding
related_issuesto autocomplete fields provides better UX when linking pull requests to issues in the admin interface. The field is properly defined via the recent migration.backend/apps/github/Makefile (1)
21-23: LGTM!The new
github-update-pull-requeststarget follows the established pattern of other GitHub management commands in this Makefile and provides a convenient interface for linking pull requests to issues.frontend/src/app/mentorship/programs/[programKey]/page.tsx (1)
9-9: LGTM: Consistent capitalization with new utility.The replacement of lodash's
upperFirstwithtitleCaseWordapplies proper title casing ("BEGINNER"→"Beginner"), whereasupperFirstwould only uppercase the first character without lowercasing the rest. This is appropriate for displaying enum values in a user-friendly format.Also applies to: 73-73, 79-79
frontend/src/app/mentorship/programs/[programKey]/modules/[moduleKey]/page.tsx (1)
9-9: LGTM: Consistent capitalization applied.Consistent with the program details page, the module's experience level now uses
titleCaseWordfor proper title casing.Also applies to: 52-52
backend/apps/mentorship/models/__init__.py (1)
1-1: LGTM: Standard public model export.The public export of
IssueUserInterestfollows Django conventions, enabling clean imports (from mentorship.models import IssueUserInterest) throughout the codebase.frontend/src/types/issue.ts (1)
1-1: LGTM: Type definition matches backend schema.The optional
pullRequestsfield correctly reflects the new Many-to-Many relationship between issues and pull requests introduced in the backend. The optional typing is appropriate since not all issues will have related PRs.Also applies to: 13-13
backend/apps/mentorship/utils.py (1)
4-6: LGTM: Robust normalization utility.The use of
casefold()instead oflower()is a good choice for case-insensitive normalization, as it handles Unicode characters more aggressively (e.g., Germanßbecomesss). The implementation gracefully handlesNoneinputs.backend/apps/github/admin/__init__.py (1)
3-3: LGTM: Standard admin export.The public export of
CommentAdminfollows the established pattern for Django admin module organization.backend/apps/github/models/pull_request.py (1)
64-69: LGTM: Well-defined Many-to-Many relationship.The
related_issuesfield correctly establishes a Many-to-Many relationship between pull requests and issues with appropriate configuration:
blank=Trueallows PRs without linked issuesrelated_name="pull_requests"provides the reverse accessor fromIssue- Aligns with migration 0038 and frontend type definitions
frontend/src/app/mentorship/programs/page.tsx (1)
53-53: LGTM: Simplified and consistent grid layout.The grid layout changes create more uniform spacing with
gap-6and streamline the responsive behavior by removing the 4-column layout on very large screens. This aligns with similar layout standardizations across other mentorship pages in this PR.
| relevant_issues = Issue.objects.filter( | ||
| repository_id__in=module_repos, state=Issue.State.OPEN | ||
| ).distinct() | ||
|
|
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.
Restrict comment sync to module-linked issues
This query pulls every open issue from the module’s repositories, including ones that aren’t tagged for the module. That creates interest records for unrelated work and burns unnecessary GitHub API quota. Use the curated module.issues relation (populated by the sync command) so we only touch issues intentionally linked to the module.
- relevant_issues = Issue.objects.filter(
- repository_id__in=module_repos, state=Issue.State.OPEN
- ).distinct()
+ relevant_issues = module.issues.filter(state=Issue.State.OPEN).distinct()📝 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.
| relevant_issues = Issue.objects.filter( | |
| repository_id__in=module_repos, state=Issue.State.OPEN | |
| ).distinct() | |
| relevant_issues = module.issues.filter(state=Issue.State.OPEN).distinct() |
🤖 Prompt for AI Agents
In backend/apps/mentorship/management/commands/mentorship_update_comments.py
around lines 70 to 73, the current query fetches every open issue in the module
repositories (repository_id__in=module_repos) which pulls unrelated issues;
replace that with the curated relation to only process module-linked issues: use
module.issues.filter(state=Issue.State.OPEN).distinct() (or the equivalent
manager access) so only intentionally linked issues are synchronized; ensure
`module` is the same object in scope and drop the repository_id filter.
frontend/src/app/my/mentorship/programs/[programKey]/modules/create/page.tsx
Show resolved
Hide resolved
|




Proposed change
Resolves #2239
Tasks