-
Notifications
You must be signed in to change notification settings - Fork 3.2k
[WEB-5871] chore: added intake count for projects #8497
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
base: preview
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughAdds a pending-intake aggregation to Project API responses, exposes Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as Client (UI)
participant Sidebar as Frontend Sidebar
participant Store as Frontend Store
participant API as Project/Inbox API
participant DB as Database
Browser ->> Sidebar: render workspace
Sidebar ->> API: GET /projects (request intake_count)
API ->> DB: query Projects with Count(project_intakeissue where status=PENDING) as intake_count
DB -->> API: project rows with intake_count
API -->> Sidebar: projects JSON (includes intake_count)
Sidebar ->> Browser: render navigation, show badge when intake_count > 0
Browser ->> Store: create/update/delete inbox issue
Store ->> API: POST/PUT/DELETE /inbox-issues
API ->> DB: persist change, return issue with status
DB -->> API: result
API -->> Store: issue response
Store ->> Store: if status transitioned to/from PENDING, adjust project.intake_count locally
Store ->> Sidebar: propagate projectMap change
Sidebar ->> Browser: update badge count
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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: 0
🧹 Nitpick comments (2)
apps/api/plane/app/views/project/base.py (2)
36-36: Consider removing unused import.The
IntakeIssuemodel is imported but not directly referenced in this file. TheCount("project_intakeissue")annotation uses the related name string directly, so this import isn't required.
137-207: Consider adding intake_count to other list methods for consistency.The
intake_countannotation is added only in thelist()method but not inlist_detail()(line 97) or the baseget_queryset()method (line 47). This creates an inconsistency where different endpoints return different fields.If
intake_countis a useful metric, consider whether it should be available inlist_detail()as well, either by:
- Adding the annotation to
get_queryset()(though this would affect all queryset usages)- Adding the annotation in
list_detail()similar to how it's done inlist()- Ensuring
ProjectListSerializercan handle the field if it's added to the queryset
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/api/plane/app/views/project/base.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-29T09:17:54.815Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7905
File: apps/api/plane/app/views/search/base.py:241-276
Timestamp: 2025-10-29T09:17:54.815Z
Learning: In apps/api/plane/app/views/search/base.py, the `filter_intakes` method uses `Issue.objects` (base manager) instead of `Issue.issue_objects` (custom manager) because the custom manager filters out all intake statuses, which would prevent querying pending and snoozed intake issues.
Applied to files:
apps/api/plane/app/views/project/base.py
📚 Learning: 2025-12-23T14:18:32.899Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/models/api.py:35-35
Timestamp: 2025-12-23T14:18:32.899Z
Learning: Django REST Framework rate limit strings are flexible: only the first character of the time unit matters. Acceptable formats include: "60/s", "60/sec", "60/second" (all equivalent), "60/m", "60/min", "60/minute" (all equivalent), "60/h", "60/hr", "60/hour" (all equivalent), and "60/d", "60/day" (all equivalent). Abbreviations like "min" are valid and do not need to be changed to "minute". Apply this guidance to any Python files in the project that configure DRF throttling rules.
Applied to files:
apps/api/plane/app/views/project/base.py
🧬 Code graph analysis (1)
apps/api/plane/app/views/project/base.py (1)
apps/api/plane/db/models/intake.py (1)
IntakeIssue(46-80)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/api/plane/app/views/project/base.py (2)
166-166: LGTM!Correctly includes the annotated
intake_countfield in the values projection.
155-155: The annotationCount("project_intakeissue")is correct. The related_name is automatically generated byProjectBaseModel, which definesrelated_name="project_%(class)s"on the project foreign key. ForIntakeIssue, this expands to"project_intakeissue".Likely an incorrect or invalid review comment.
|
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
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 (1)
apps/web/core/components/workspace/sidebar/project-navigation.tsx (1)
179-187: Consider adding accessibility attributes for the count badge.The layout restructure works well and the conditional count display is implemented correctly. However, consider adding an
aria-labelto the count badge for better screen reader support.♿ Optional accessibility enhancement
- {shouldShowCount && <span className="text-11 font-medium text-tertiary">{project.intake_count}</span>} + {shouldShowCount && ( + <span className="text-11 font-medium text-tertiary" aria-label={`${project.intake_count} intake items`}> + {project.intake_count} + </span> + )}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/core/components/workspace/sidebar/project-navigation.tsxpackages/types/src/project/projects.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}
📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)
**/*.{ts,tsx,mts,cts}: Useconsttype parameters for more precise literal inference in TypeScript 5.0+
Use thesatisfiesoperator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicitisreturn types in filter/check functions
UseNoInfer<T>utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing inswitch(true)blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacyexperimentalDecorators
Useusingdeclarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Usewith { type: "json" }for import attributes; avoid deprecatedassertsyntax (TypeScript 5.3/5.8+)
Useimport typeexplicitly when importing types to ensure they are erased during compilation, respectingverbatimModuleSyntaxflag
Use.ts,.mts,.ctsextensions inimport typestatements (TypeScript 5.2+)
Useimport type { Type } from "mod" with { "resolution-mode": "import" }for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize newSetmethods likeunion,intersection, etc., when available (TypeScript 5.5+)
UseObject.groupBy/Map.groupBystandard methods for grouping instead of external libraries (TypeScript 5.4+)
UsePromise.withResolvers()for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted,toSpliced,with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields viasuperin classes (TypeScript 5....
Files:
apps/web/core/components/workspace/sidebar/project-navigation.tsxpackages/types/src/project/projects.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Enable TypeScript strict mode and ensure all files are fully typed
Files:
apps/web/core/components/workspace/sidebar/project-navigation.tsxpackages/types/src/project/projects.ts
**/*.{js,jsx,ts,tsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Prettier with Tailwind plugin for code formatting, run
pnpm fix:format
Files:
apps/web/core/components/workspace/sidebar/project-navigation.tsxpackages/types/src/project/projects.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately
Files:
apps/web/core/components/workspace/sidebar/project-navigation.tsxpackages/types/src/project/projects.ts
🧠 Learnings (2)
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Sidebar menu items should use transparent backgrounds with hover states like `hover:bg-layer-1-hover` rather than base layer backgrounds, maintaining visual lightness while providing hover feedback
Applied to files:
apps/web/core/components/workspace/sidebar/project-navigation.tsx
📚 Learning: 2025-06-16T07:23:39.497Z
Learnt from: vamsikrishnamathala
Repo: makeplane/plane PR: 7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Applied to files:
packages/types/src/project/projects.ts
🧬 Code graph analysis (1)
apps/web/core/components/workspace/sidebar/project-navigation.tsx (2)
apps/web/core/components/sidebar/sidebar-navigation.tsx (1)
SidebarNavItem(9-25)packages/i18n/src/store/index.ts (1)
t(222-243)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Build packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
packages/types/src/project/projects.ts (1)
36-36: LGTM! Well-typed optional field addition.The optional
intake_countfield is appropriately typed and maintains backward compatibility. The snake_case convention matches the existing interface style.apps/web/core/components/workspace/sidebar/project-navigation.tsx (1)
174-174: LGTM! Correct nullish coalescing usage.The logic correctly handles the optional
intake_countfield using the nullish coalescing operator and only displays the count for the intake item when it's greater than zero.
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: 1
🤖 Fix all issues with AI agents
In @apps/api/plane/app/views/project/base.py:
- Around line 156-160: The intake_count annotation is only added in list()
causing missing field in list_detail() and retrieve(); move the Count(...)
annotation into get_queryset() so every endpoint using self.get_queryset()
(including list_detail and retrieve) gets intake_count, remove the duplicate
annotate call from list() (but keep "intake_count" in list()'s values() call),
and ensure the annotation uses the same Count call with
filter=Q(project_intakeissue__status=IntakeIssueStatus.PENDING.value) and the
same alias intake_count so field names remain consistent across endpoints.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/api/plane/app/views/project/base.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-29T09:17:54.815Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7905
File: apps/api/plane/app/views/search/base.py:241-276
Timestamp: 2025-10-29T09:17:54.815Z
Learning: In apps/api/plane/app/views/search/base.py, the `filter_intakes` method uses `Issue.objects` (base manager) instead of `Issue.issue_objects` (custom manager) because the custom manager filters out all intake statuses, which would prevent querying pending and snoozed intake issues.
Applied to files:
apps/api/plane/app/views/project/base.py
📚 Learning: 2025-12-23T14:18:32.899Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/models/api.py:35-35
Timestamp: 2025-12-23T14:18:32.899Z
Learning: Django REST Framework rate limit strings are flexible: only the first character of the time unit matters. Acceptable formats include: "60/s", "60/sec", "60/second" (all equivalent), "60/m", "60/min", "60/minute" (all equivalent), "60/h", "60/hr", "60/hour" (all equivalent), and "60/d", "60/day" (all equivalent). Abbreviations like "min" are valid and do not need to be changed to "minute". Apply this guidance to any Python files in the project that configure DRF throttling rules.
Applied to files:
apps/api/plane/app/views/project/base.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check:lint
- GitHub Check: check:types
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/api/plane/app/views/project/base.py (2)
7-7: LGTM: Imports are correct.The new imports (
Count,IntakeIssue,IntakeIssueStatus) are all used in the intake_count annotation and are appropriately placed.Also applies to: 36-36, 38-38
156-160: The related name "project_intakeissue" is correct and the Count aggregation introduces no N+1 query issues.The IntakeIssue model extends ProjectBaseModel, which uses
related_name="project_%(class)s". This automatically generates the reverse accessor as "project_intakeissue" (the model name in lowercase), matching the annotation in your code. The Count aggregation with filter executes as a single annotation on the main queryset without additional queries per result.
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 (2)
apps/web/core/store/inbox/project-inbox.store.ts (1)
470-474: Consider extracting intake count update logic to a helper method.The pattern for reading and updating
intake_countis repeated across both create and delete operations, and will be even more prevalent when combined with the status transition logic ininbox-issue.store.ts. Consider extracting this to a helper method like:private updateProjectIntakeCount(projectId: string, delta: number): void { const currentCount = this.store.projectRoot.project.projectMap[projectId]?.intake_count ?? 0; set( this.store.projectRoot.project.projectMap, [projectId, "intake_count"], Math.max(0, currentCount + delta) ); }Then use it as
this.updateProjectIntakeCount(projectId, 1)orthis.updateProjectIntakeCount(projectId, -1).Also applies to: 507-511
apps/web/core/store/inbox/inbox-issue.store.ts (1)
105-121: Consider extracting the intake count update pattern to reduce duplication.The pattern for updating
intake_countappears 6 times across the three status update methods in this file, and additional times inproject-inbox.store.ts. This duplication increases maintenance overhead.♻️ Suggested refactoring approach
Consider adding a private helper method to encapsulate the intake count update logic:
private adjustProjectIntakeCount(delta: 1 | -1): void { const currentCount = this.store.projectRoot.project.projectMap[this.projectId]?.intake_count ?? 0; set( this.store.projectRoot.project.projectMap, [this.projectId, "intake_count"], Math.max(0, currentCount + delta) ); }Then replace the repeated blocks with:
// Decrementing this.adjustProjectIntakeCount(-1); // Incrementing this.adjustProjectIntakeCount(1);This would reduce the code size and make future modifications to the intake count logic easier to maintain consistently.
Also applies to: 152-160, 187-198
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/core/store/inbox/inbox-issue.store.tsapps/web/core/store/inbox/project-inbox.store.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}
📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)
**/*.{ts,tsx,mts,cts}: Useconsttype parameters for more precise literal inference in TypeScript 5.0+
Use thesatisfiesoperator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicitisreturn types in filter/check functions
UseNoInfer<T>utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing inswitch(true)blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacyexperimentalDecorators
Useusingdeclarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Usewith { type: "json" }for import attributes; avoid deprecatedassertsyntax (TypeScript 5.3/5.8+)
Useimport typeexplicitly when importing types to ensure they are erased during compilation, respectingverbatimModuleSyntaxflag
Use.ts,.mts,.ctsextensions inimport typestatements (TypeScript 5.2+)
Useimport type { Type } from "mod" with { "resolution-mode": "import" }for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize newSetmethods likeunion,intersection, etc., when available (TypeScript 5.5+)
UseObject.groupBy/Map.groupBystandard methods for grouping instead of external libraries (TypeScript 5.4+)
UsePromise.withResolvers()for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted,toSpliced,with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields viasuperin classes (TypeScript 5....
Files:
apps/web/core/store/inbox/inbox-issue.store.tsapps/web/core/store/inbox/project-inbox.store.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Enable TypeScript strict mode and ensure all files are fully typed
Files:
apps/web/core/store/inbox/inbox-issue.store.tsapps/web/core/store/inbox/project-inbox.store.ts
**/*.{js,jsx,ts,tsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Prettier with Tailwind plugin for code formatting, run
pnpm fix:format
Files:
apps/web/core/store/inbox/inbox-issue.store.tsapps/web/core/store/inbox/project-inbox.store.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately
Files:
apps/web/core/store/inbox/inbox-issue.store.tsapps/web/core/store/inbox/project-inbox.store.ts
🧠 Learnings (1)
📚 Learning: 2025-06-16T07:23:39.497Z
Learnt from: vamsikrishnamathala
Repo: makeplane/plane PR: 7214
File: web/core/store/issue/helpers/base-issues.store.ts:117-117
Timestamp: 2025-06-16T07:23:39.497Z
Learning: In the updateIssueDates method of BaseIssuesStore (web/core/store/issue/helpers/base-issues.store.ts), the projectId parameter is intentionally made optional to support override implementations in subclasses. The base implementation requires projectId and includes an early return check, but making it optional allows derived classes to override the method with different parameter requirements.
Applied to files:
apps/web/core/store/inbox/project-inbox.store.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check:types
- GitHub Check: check:lint
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/web/core/store/inbox/project-inbox.store.ts (2)
470-474: LGTM! Intake count incremented correctly for new PENDING issues.The logic correctly increments
intake_countwhen a new inbox issue is created with PENDING status. The defensive?? 0fallback handles cases where the project hasn't been loaded yet orintake_countis undefined.
491-491: LGTM! Intake count decremented correctly with proper safeguards.The implementation correctly captures the
wasPendingstate before the asynchronous deletion and decrementsintake_countonly after successful deletion. The use ofMath.max(0, currentCount - 1)prevents negative counts.Also applies to: 507-511
apps/web/core/store/inbox/inbox-issue.store.ts (3)
97-97: LGTM! Bidirectional status transitions handled correctly.The implementation correctly captures
previousStatusbefore the async update and properly handles both directions of status transitions:
- Transitioning away from PENDING: decrements intake_count
- Transitioning to PENDING: increments intake_count
The use of
Math.max(0, ...)when decrementing prevents negative counts, and the logic executes only after a successful API response.Also applies to: 105-122
141-141: LGTM! Duplicate marking correctly decrements intake count.The implementation correctly captures the
wasPendingstate and decrementsintake_countonly when the issue was previously PENDING. Since marking as DUPLICATE always transitions away from PENDING (when applicable), the unidirectional decrement logic is appropriate.Also applies to: 152-160
177-177: LGTM! Snooze transitions handle intake count correctly.The implementation properly handles both snoozing and unsnoozing:
- Snoozing (PENDING → SNOOZED): decrements intake_count
- Unsnoozing (any status → PENDING): increments intake_count if not already PENDING
The
previousStatuscapture ensures correct state tracking across the async operation.Also applies to: 187-198
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: 1
🤖 Fix all issues with AI agents
In @apps/api/plane/app/views/project/base.py:
- Around line 155-163: The intake_count annotation is applied only in list()
using the related_name project_intakeissue, causing inconsistency for
retrieve/list_detail; move the Count annotation (the intake_count calculation
using Count("project_intakeissue",
filter=Q(project_intakeissue__status=IntakeIssueStatus.PENDING.value,
project_intakeissue__deleted_at__isnull=True))) into get_queryset() so all
endpoints that use ProjectListSerializer receive the field consistently;
additionally, add a DB index on IntakeIssue covering (project_id, status,
deleted_at) in the IntakeIssue model/migration to optimize the filtered Count
aggregation.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/api/plane/app/views/project/base.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-29T09:17:54.815Z
Learnt from: NarayanBavisetti
Repo: makeplane/plane PR: 7905
File: apps/api/plane/app/views/search/base.py:241-276
Timestamp: 2025-10-29T09:17:54.815Z
Learning: In apps/api/plane/app/views/search/base.py, the `filter_intakes` method uses `Issue.objects` (base manager) instead of `Issue.issue_objects` (custom manager) because the custom manager filters out all intake statuses, which would prevent querying pending and snoozed intake issues.
Applied to files:
apps/api/plane/app/views/project/base.py
📚 Learning: 2025-12-23T14:18:32.899Z
Learnt from: dheeru0198
Repo: makeplane/plane PR: 8339
File: apps/api/plane/db/models/api.py:35-35
Timestamp: 2025-12-23T14:18:32.899Z
Learning: Django REST Framework rate limit strings are flexible: only the first character of the time unit matters. Acceptable formats include: "60/s", "60/sec", "60/second" (all equivalent), "60/m", "60/min", "60/minute" (all equivalent), "60/h", "60/hr", "60/hour" (all equivalent), and "60/d", "60/day" (all equivalent). Abbreviations like "min" are valid and do not need to be changed to "minute". Apply this guidance to any Python files in the project that configure DRF throttling rules.
Applied to files:
apps/api/plane/app/views/project/base.py
🧬 Code graph analysis (1)
apps/api/plane/app/views/project/base.py (1)
apps/api/plane/db/models/intake.py (1)
IntakeIssueStatus(38-43)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: check:types
- GitHub Check: check:lint
- GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
apps/api/plane/app/views/project/base.py (3)
7-7: LGTM! Import addition is correct.The
Countimport is necessary for the intake count aggregation and is correctly placed with other Django ORM imports.
174-174: LGTM! Field projection is correct.The
intake_countfield is correctly included in thevalues()projection to ensure the computed annotation is returned in the API response.
37-37: Import is correct and necessary.The
IntakeIssueStatusenum is properly defined withPENDING = -2, and the model's status field default and choices are aligned. Usage at line 159 correctly applies.valueto filter pending intake issues.
| .annotate( | ||
| intake_count=Count( | ||
| "project_intakeissue", | ||
| filter=Q( | ||
| project_intakeissue__status=IntakeIssueStatus.PENDING.value, | ||
| project_intakeissue__deleted_at__isnull=True, | ||
| ), | ||
| ) | ||
| ) |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the IntakeIssue model to verify the related_name
fd -t f ".*intake.*\.py" --type f | grep -iE "model|intake" | head -20Repository: makeplane/plane
Length of output: 487
🏁 Script executed:
#!/bin/bash
# Search for IntakeIssue class definition
rg -l "class IntakeIssue" --type pyRepository: makeplane/plane
Length of output: 329
🏁 Script executed:
#!/bin/bash
# Look at the views file structure to understand methods
cat -n apps/api/plane/app/views/project/base.py | head -250Repository: makeplane/plane
Length of output: 10640
🏁 Script executed:
#!/bin/bash
# Find the IntakeIssue model definition and check the foreign key to Project
cat -n apps/api/plane/db/models/intake.py | head -150Repository: makeplane/plane
Length of output: 3137
🏁 Script executed:
#!/bin/bash
# Search for the related_name in the IntakeIssue model
rg "related_name" apps/api/plane/db/models/intake.py -A 2 -B 2Repository: makeplane/plane
Length of output: 500
🏁 Script executed:
#!/bin/bash
# Check ProjectListSerializer to see if it includes intake_count
rg -A 30 "class ProjectListSerializer" apps/api/plane/app/serializers/Repository: makeplane/plane
Length of output: 2791
🏁 Script executed:
#!/bin/bash
# Check ProjectBaseModel to see how project FK is defined
rg -A 10 "class ProjectBaseModel" apps/api/plane/db/models/ --type py | head -30Repository: makeplane/plane
Length of output: 890
🏁 Script executed:
#!/bin/bash
# Search for IntakeIssue's project field or check if it's inherited
rg "project.*IntakeIssue\|IntakeIssue.*project" apps/api/plane/db/models/ --type py -A 2 -B 2Repository: makeplane/plane
Length of output: 41
🏁 Script executed:
#!/bin/bash
# Check if there are any database migrations that show the related_name
rg "IntakeIssue" apps/api/plane/db/migrations/0085_intake_intakeissue_remove_inboxissue_created_by_and_more.py -A 5 -B 5 | head -100Repository: makeplane/plane
Length of output: 2070
🏁 Script executed:
#!/bin/bash
# Check database indexes on IntakeIssue table
rg -A 5 "class IntakeIssue" apps/api/plane/db/models/intake.py | grep -A 20 "class Meta"Repository: makeplane/plane
Length of output: 41
🏁 Script executed:
#!/bin/bash
# Search for any index definitions in migrations or models for IntakeIssue
rg "IntakeIssue.*index\|index.*IntakeIssue" apps/api/plane/db/ --type pyRepository: makeplane/plane
Length of output: 41
🏁 Script executed:
#!/bin_bash
# Check the full serializer definition to see all fields
cat -n apps/api/plane/app/serializers/project.py | grep -A 50 "class ProjectListSerializer"Repository: makeplane/plane
Length of output: 2420
🏁 Script executed:
#!/bin/bash
# Final check: verify that ProjectBaseModel's related_name pattern works for IntakeIssue
# and that there's no explicit related_name override in IntakeIssue model
grep -n "class IntakeIssue\|related_name\|project" apps/api/plane/db/models/intake.py | head -20Repository: makeplane/plane
Length of output: 690
🏁 Script executed:
#!/bin/bash
# Check if get_queryset needs the intake_count annotation for consistency
# by seeing if list_detail and retrieve should return it
grep -n "intake_count" apps/api/plane/app/ -r --type pyRepository: makeplane/plane
Length of output: 176
🏁 Script executed:
#!/bin/bash
# Check where intake_count is referenced in the codebase
rg "intake_count" apps/api/plane/ --type pyRepository: makeplane/plane
Length of output: 204
🏁 Script executed:
#!/bin/bash
# Look at the Project model to see if intake_count is a real model field
rg -A 5 "class Project" apps/api/plane/db/models/project.py | head -50Repository: makeplane/plane
Length of output: 2135
The relationship name is correct, but consider consistency and indexes.
The annotation correctly uses project_intakeissue as the related_name, which is automatically generated by ProjectBaseModel's pattern related_name="project_%(class)s" for the IntakeIssue model.
However, two legitimate concerns remain:
-
Inconsistency across endpoints: The
intake_countannotation is only added to thelist()method (lines 155-163) but not toget_queryset(). This meanslist_detail()andretrieve()won't includeintake_countin their responses even though they use the sameProjectListSerializer. If the frontend expects this field consistently, move the annotation toget_queryset(). -
Missing database indexes: For optimal performance, add indexes on IntakeIssue table for
(project_id, status, deleted_at)to support the Count aggregation with filters.
🤖 Prompt for AI Agents
In @apps/api/plane/app/views/project/base.py around lines 155 - 163, The
intake_count annotation is applied only in list() using the related_name
project_intakeissue, causing inconsistency for retrieve/list_detail; move the
Count annotation (the intake_count calculation using
Count("project_intakeissue",
filter=Q(project_intakeissue__status=IntakeIssueStatus.PENDING.value,
project_intakeissue__deleted_at__isnull=True))) into get_queryset() so all
endpoints that use ProjectListSerializer receive the field consistently;
additionally, add a DB index on IntakeIssue covering (project_id, status,
deleted_at) in the IntakeIssue model/migration to optimize the filtered Count
aggregation.
Description
This PR will show the intake count for projects
Below is the number of queries the project list endpoint hits with the added logic to fetch the intake count. Tested with more than hundreds of intake issues and no N+1 queries.
Type of Change
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.