Fix/added property type prop deployment ts error#6856
Fix/added property type prop deployment ts error#6856naman-agrawal-shipsy wants to merge 193 commits intomakeplane:previewfrom
Conversation
Changes to support multipart data in nginx config files
…rnames Filter the issues with usernames from headers( X-Assume-Role)
Editable custom property fields
…down Disable the dropdown of workspaces
Fix for filteting the issues by type_id
Multiple user login fix
Added four new fileds to issue model and added filteration
…perties added new fileds to display properties
Editable custom property fields
…perties Dr iss 266189 addednewto display properties
…-in-properties Added 4 additional properties (names) in fixed issue properties
WalkthroughThis pull request introduces extensive enhancements and refactoring across backend, frontend, deployment, and configuration files. Major changes include new Docker commands and CMD instructions, expanded API endpoints with custom property handling, updates to serializers, URL routing, and view logic. Multiple Django migrations adjust the database schema for issue and project custom properties. The codebase also receives numerous updates to React components and filtering functionality along with adjustments in permissions, authentication flows, CI/CD pipelines, and configuration files. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant APIView as IssueCustomPropertyUpdateAPIView
participant Serializer
participant DB
Client->>APIView: Send PATCH request with custom property data
APIView->>Serializer: Validate and process request
Serializer->>DB: Update Issue & Custom Property records
DB-->>Serializer: Return updated records
Serializer-->>APIView: Serialize updated response
APIView-->>Client: Return success response
Possibly related PRs
Suggested reviewers
Poem
✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 42
🔭 Outside diff range comments (4)
web/core/components/workspace/sidebar/help-section.tsx (1)
31-32: 💡 Verification agent🧩 Analysis chain
Verify used hooks and state.
With the removal of the help menu functionality, check if
isIntercomToggle,toggleIntercom,canUseLocalDB, andtoggleLocalDBhooks are still needed in this component.
🏁 Script executed:
#!/bin/bash # Search for references to these hooks and state in this file # to verify if they're still used after the changes rg -A 3 "toggleIntercom|isIntercomToggle|canUseLocalDB|toggleLocalDB" web/core/components/workspace/sidebar/help-section.tsxLength of output: 488
Action: Remove Unused LocalDB Hooks
After verifying the code, it appears that while the intercom hooks (
isIntercomToggleandtoggleIntercom) are actively used (e.g., in thetoggleIntercom(!isIntercomToggle)call), the localDB hooks (canUseLocalDBandtoggleLocalDB) are destructured but not used anywhere in the component. Please verify if these localDB hooks are intended for future use. If not, removing them will clean up the code.
- File:
web/core/components/workspace/sidebar/help-section.tsx- Location: Lines 31-32 and their usage below
- Suggestion: Remove the destructuring of
canUseLocalDBandtoggleLocalDBfromuseUserSettingsif they are no longer needed.apiserver/plane/app/permissions/project.py (1)
119-153: 🛠️ Refactor suggestionConsider unifying with
ProjectEntityPermission.This entire new class duplicates much permission logic. Factor shared logic into a helper or base class to avoid repeated code and reduce the chance of drift.
apiserver/plane/app/views/view/base.py (1)
209-306: 💡 Verification agent🧩 Analysis chain
Method signature change requires careful integration.
The method signature has changed from
def get_queryset(self)todef get_queryset(self, filters), which could break backward compatibility if this method is called elsewhere without the new parameter.Also, the custom properties filtering implementation looks good, but make sure all callers provide the required filters parameter.
🏁 Script executed:
#!/bin/bash # Search for any direct calls to get_queryset in this class that might not pass the filters parameter rg "\.get_queryset\(\)" --type py | grep -v "super\(\)"Length of output: 8721
Action Required: Address Backward Compatibility for
get_querysetSignature ChangeThe change of the method signature from
def get_queryset(self)todef get_queryset(self, filters)introduces a potential backward compatibility issue. The shell script output shows many call sites across the repository (e.g., in modules underapiserver/plane/space/views,apiserver/plane/api/views, etc.) that still invoke.get_queryset()without supplying the requiredfiltersparameter. This will likely lead to runtime errors.Recommendations:
- Update Call Sites: Go through the identified files and update all calls to
.get_queryset()by providing the appropriate filters (e.g., an empty dictionary{}when no filters are needed).- Consider a Fallback: If it's desirable for backward compatibility, consider modifying the method signature to include a default value (e.g.,
def get_queryset(self, filters={})), ensuring that all existing usages remain functional.apiserver/plane/api/views/search.py (1)
236-275: 🛠️ Refactor suggestionEnsure broader coverage in global search.
Currently, the
MODELS_MAPPERonly has"issue"active while others are commented out. For true global search, consider uncommenting and supporting those entity filters. Also, retrievingcreated_by_usernamefrom request headers may be unconventional—query parameters might be more standard and explicit.
🧹 Nitpick comments (95)
web/app/provider.tsx (4)
54-54: Remove console logging before pushing to production.This debug statement should be removed before the code is deployed to production, as it leaks information about user navigation and decreases performance.
- console.log(pathname, 'pathname');
60-60: Remove console logging before pushing to production.This debug statement should be removed before the code is deployed to production, as it could leak sensitive information and impact performance.
- console.log('onIncomingMessage', event);
65-65: Improve error handling in the catch block.The current implementation has an empty catch block which silently swallows errors. This may make debugging difficult in the future.
- } catch (err) {} + } catch (err) { + console.error("Error during sign out:", err); + window.parent.postMessage({ type: "PLANE_SIGN_OUT_ERROR", error: err.message }, trustedOrigin); + }
72-72: Update useEffect dependencies.The effect depends on
pathnameandhandleSignOutbut they're not included in the dependency array. This could cause stale values to be used if these values change.- }, []); + }, [pathname, handleSignOut]);web/core/components/workspace/sidebar/help-section.tsx (5)
6-8: Remove unused imports.After removing the
CustomMenucomponent and its associated menu items, several imports are no longer used in this file:
FileText,HelpCircle,MessagesSquare,Userfrom lucide-reactCustomMenufrom @plane/uiConsider removing these unused imports to keep the codebase clean.
-import { FileText, HelpCircle, MessagesSquare, MoveLeft, User } from "lucide-react"; +import { MoveLeft } from "lucide-react"; // ui -import { CustomMenu, Tooltip, ToggleSwitch } from "@plane/ui"; +import { Tooltip } from "@plane/ui";
34-35: Remove unused state variables.The state variables
isNeedHelpOpenandisChangeLogOpenappear to be unused or partially unused after removing the help menu functionality. TheisChangeLogOpenis still used for theProductUpdatesModal, butisNeedHelpOpendoesn't seem to be used anywhere now.// states - const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false); const [isChangeLogOpen, setIsChangeLogOpen] = useState(false);
37-39: Remove unused function.The
handleCrispWindowShowfunction is no longer used after removing the help menu functionality. Consider removing it to improve code maintainability.- const handleCrispWindowShow = () => { - toggleIntercom(!isIntercomToggle); - };
54-56: Justify UI layout change.The layout has been adjusted to use
justify-end ml-autoinstead of the previous spacing distribution. This aligns the collapse button to the right side of the sidebar when not collapsed.While this change is valid, consider documenting the reason for this UI adjustment, especially since it changes the visual layout of a component that users interact with frequently.
43-72: Consider alternatives for removed help functionality.The removal of the help menu items reduces the accessibility of important resources like documentation, support messaging, and keyboard shortcuts. Consider adding an alternative way for users to access these resources, perhaps through a main navigation item or a different UI component.
apiserver/plane/api/urls/search.py (1)
8-12: URL pattern name doesn't match endpoint purpose.The URL pattern for the search endpoint is named "project", which doesn't reflect its actual functionality. A more descriptive name like "global_search" would improve clarity and maintainability.
path( "workspaces/<str:slug>/search/", GlobalSearchEndpoint.as_view(), - name="project", + name="global_search", ),apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py (2)
19-21: Fix spelling error inrelated_nameparameterThere's a spelling error in the
related_nameparameter: "custom_propery_issue_type" should be "custom_property_issue_type".- field=models.ManyToManyField(related_name='custom_propery_issue_type', to='db.issuetype'), + field=models.ManyToManyField(related_name='custom_property_issue_type', to='db.issuetype'),
6-22: Consider consolidating related migrationsThis migration appears to be the first in a sequence of 6 migrations (0085-0090) that make related changes to the same models. From the context provided, the subsequent migrations rename fields, correct spelling errors, and make additional changes to the same models modified here.
For cleaner schema evolution and easier maintenance, consider consolidating these related migrations into fewer, more comprehensive migrations. This helps reduce the complexity and potential issues when applying migrations in different environments.
apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
14-18: New field addition looks good, but be aware of subsequent migrationsThe addition of the
issue_typeforeign key field to theissuecustompropertymodel with appropriate null and blank settings is well implemented. However, note that subsequent migrations (0088-0090) show this field will undergo multiple revisions - first changing its reference fromissuetypetoissuetypecustompropertyand then renaming it.Consider consolidating these sequential migrations into a single migration before merging to production to minimize migration overhead.
web/core/hooks/use-group-dragndrop.ts (1)
64-65: Good fix for type consistency in key checksConverting
moduleKeyandcycleKeyto strings before checking for inclusion in the data keys is a good practice that prevents type mismatch issues. This change ensures consistent comparison behavior regardless of key types.Consider adding a comment explaining why the toString() conversion is necessary for future maintainers. Also, for better type safety, you could further refine this with more explicit type checks:
-const isModuleChanged = Object.keys(data).includes(moduleKey.toString()); -const isCycleChanged = Object.keys(data).includes(cycleKey.toString()); +// Convert keys to strings to ensure consistent type comparison +const moduleKeyString = moduleKey.toString(); +const cycleKeyString = cycleKey.toString(); +const isModuleChanged = Object.keys(data).includes(moduleKeyString); +const isCycleChanged = Object.keys(data).includes(cycleKeyString);apiserver/plane/api/views/attachment.py (2)
9-9: Remove unused import.According to static analysis,
allow_permissionis imported but never used. Removing it will clean up the code.-from plane.app.permissions import ProjectEntityPermission, allow_permission +from plane.app.permissions import ProjectEntityPermission🧰 Tools
🪛 Ruff (0.8.2)
9-9:
plane.app.permissions.allow_permissionimported but unusedRemove unused import:
plane.app.permissions.allow_permission(F401)
167-169: Reevaluate overwriting 'created_by' on patch.When marking the attachment as uploaded, you're setting
created_byto the current user, potentially overwriting the original creator. Consider using a separate field, such asuploaded_byor relying onupdated_byto track this action more accurately.apiserver/plane/authentication/utils/redirection_path.py (1)
9-10:Details
❓ Verification inconclusive
Verify onboarding bypass implications
By commenting out these lines, users will no longer be redirected to the onboarding path even if they haven't completed onboarding. Ensure this change is intentional and won't cause issues with user experience or data setup.
🏁 Script executed:
#!/bin/bash # Check if there are other places in the codebase that might depend on this onboarding redirection echo "Searching for code that references onboarding redirection..." rg -A 3 "profile.is_onboarded" --type py rg -A 3 "return \"onboarding\"" --type pyLength of output: 2225
Action: Verify Onboarding Redirection Behavior
The redirection logic in
apiserver/plane/authentication/utils/redirection_path.pyhas been disabled by commenting out the following lines:# if not profile.is_onboarded: # return "onboarding"Our search confirms that the
profile.is_onboardedflag is still actively used in other parts of the code (e.g., inapiserver/plane/app/views/user/base.py,apiserver/plane/authentication/views/app/magic.py, andapiserver/plane/api/views/member.py). This indicates that while user onboarding status is maintained and updated, the automatic redirection to the onboarding flow is now bypassed.Please verify that:
- This change is intentional and consistent with the revised onboarding flow.
- Users who have not completed onboarding are handled appropriately within the updated process.
- There are no unintended impacts on user experience or data setup due to the removal of this redirection.
If the bypass is by design, consider updating comments or documentation to clarify the intentional behavior change.
apiserver/plane/app/urls/views.py (1)
66-74: Consider using a unique name for this URL patternThe new endpoint for retrieving workspace custom properties is using the same name ('global-view-issues') as the existing endpoint on line 64. This could cause issues with Django's reverse URL lookup functionality.
path( "workspaces/<str:slug>/custom-properties/", WorkspaceViewIssuesViewSet.as_view( { "get": "listCustomProperty", } ), - name="global-view-issues", + name="global-view-custom-properties", ),apiserver/plane/api/serializers/project.py (1)
12-12: Remove unused importThe
IssueTypeSerializeris imported but not used anywhere in this file.-from .issue_type import IssueTypeSerializer🧰 Tools
🪛 Ruff (0.8.2)
12-12:
.issue_type.IssueTypeSerializerimported but unusedRemove unused import:
.issue_type.IssueTypeSerializer(F401)
apiserver/plane/app/urls/issue.py (2)
325-329: URL path missing trailing slash and using inconsistent project_id type.The search endpoint URL is missing a trailing slash, which is inconsistent with other endpoints in this file. Also, this endpoint uses
<str:project_id>while most other endpoints use<uuid:project_id>.- path( - "workspaces/<str:slug>/projects/<str:project_id>/search", - SearchAPIEndpoint.as_view(), - name="key-codes", - ), + path( + "workspaces/<str:slug>/projects/<str:project_id>/search/", + SearchAPIEndpoint.as_view(), + name="search-issues", + ),
330-334: URL path name may contain typo and uses inconsistent naming.The endpoint name "filed_search" might contain a typo (should be "field_search"?). Also, the name parameter "key-codes" doesn't seem to accurately describe the search functionality and is reused from the previous endpoint.
- path( - "workspaces/<str:slug>/projects/<str:project_id>/filed_search", - SearchSingleValueAPI.as_view(), - name="key-codes" - ) + path( + "workspaces/<str:slug>/projects/<str:project_id>/field_search/", + SearchSingleValueAPI.as_view(), + name="field-search" + )apiserver/plane/db/models/base.py (2)
36-38: Good conditional check for created_by field.The added condition prevents overwriting an existing
created_byvalue when saving an instance, which is a good improvement. However, there's some inconsistent indentation and an unnecessary blank line.- if self.created_by is None: - self.created_by = user - + if self.created_by is None: + self.created_by = user
46-48: Remove unnecessary blank lines at end of file.There are multiple blank lines at the end of the file which aren't necessary.
- - - +space/core/components/issues/filters/selection.tsx (1)
9-9: Consider removing unused import if not needed immediately.The
FilterCustomPropertycomponent is imported but not used in this file. This might be intentional for future implementation, but consider removing it if not needed immediately to avoid increasing bundle size.-import { FilterPriority, FilterState, FilterCustomProperty } from "."; +import { FilterPriority, FilterState } from ".";apiserver/plane/db/models/__init__.py (1)
44-44: Address unused imports flagged by static analysis.The imports for
IssueCustomPropertyandIssueTypeCustomPropertyare flagged as unused by static analysis. For__init__.pyfiles, imports typically serve to re-export symbols for easier access by other modules.To fix the linting warnings, you can either:
- Add the imports to
__all__variable:+__all__ = [ + # ... other imports + "IssueCustomProperty", + "IssueTypeCustomProperty", + # ... other imports +]
- Or use a redundant alias to acknowledge the purposeful re-export:
-from .issue import ( +from .issue import ( # noqa # ... other imports IssueCustomProperty ) -from .issue_type import IssueType, IssueTypeCustomProperty +from .issue_type import IssueType, IssueTypeCustomProperty # noqaAlso applies to: 115-115
🧰 Tools
🪛 Ruff (0.8.2)
44-44:
.issue.IssueCustomPropertyimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
web/core/components/issues/issue-layouts/spreadsheet/columns/standard-property-column.tsx (1)
1-22: Component structure looks good, but consider type safety improvements.The component correctly renders standard properties from issue objects in a spreadsheet layout. The use of conditional rendering with optional chaining is appropriate.
Consider adding better handling for complex property values and improving type safety:
import React from "react"; import { observer } from "mobx-react"; // types import { TIssue } from "@plane/types"; import { Row, Tooltip } from "@plane/ui"; type Props = { issue: TIssue; - property: string; + property: keyof TIssue; }; export const SpreadsheetStandardPropertyColumn: React.FC<Props> = observer((props) => { const { issue, property } = props; + // Helper to format property value for display + const getFormattedValue = () => { + const value = issue?.[property]; + if (value === null || value === undefined) return ""; + if (typeof value === "object") return JSON.stringify(value); + return String(value); + }; + + const displayValue = getFormattedValue(); return ( - <Tooltip tooltipContent={issue?.[property]} disabled={!issue?.[property]}> + <Tooltip tooltipContent={displayValue} disabled={!displayValue}> <Row className="h-11 truncate border-b-[0.5px] border-custom-border-200 pt-[1.25em] text-xs hover:bg-custom-background-80"> - {issue?.[property]} + {displayValue} </Row> </Tooltip> ); });apiserver/plane/db/migrations/0091_issue_customer_code_issue_hub_code_and_more.py (1)
13-42: Consider adding indexes for frequent lookups.Each new field is configured with
blank=True, null=True. If you plan to filter or query issues by any of these codes, adding a database index can enhance performance.To add an index, apply a similar patch to each added field:
migrations.AddField( model_name='issue', name='customer_code', - field=models.CharField(blank=True, max_length=255, null=True), + field=models.CharField(db_index=True, blank=True, max_length=255, null=True), ),apiserver/plane/api/urls/__init__.py (1)
9-10: Fix spelling of imported and expanded patterns.The variable name "
patters" appears to be a typo. Correcting it to "patterns" improves clarity and consistency.Apply the following diff at both the import and usage sites:
-from .search import urlpatterns as search_patters -from .webhook import urlpatterns as webhook_patters +from .search import urlpatterns as search_patterns +from .webhook import urlpatterns as webhook_patterns ... *issue_type_patterns, - *search_patters, - *webhook_patters + *search_patterns, + *webhook_patternsAlso applies to: 20-22
apiserver/plane/api/serializers/issue_type.py (2)
1-1: Remove unused importThe
serializersmodule fromrest_frameworkis imported but not directly used in the code. You should remove unused imports to keep the codebase clean.-from rest_framework import serializers🧰 Tools
🪛 Ruff (0.8.2)
1-1:
rest_framework.serializersimported but unusedRemove unused import:
rest_framework.serializers(F401)
26-44: Check for potential inconsistency in create methodThe create method adds the issue_type_id from context, but this field is also in the read_only_fields list. While this approach works, it might be clearer to handle this similarly to how workspace_id is handled in the IssueTypeSerializer (via validate method).
Consider refactoring to use the validate method approach for consistency:
class IssueTypeCustomPropertySerializer(BaseSerializer): class Meta: model = IssueTypeCustomProperty fields = "__all__" read_only_fields = [ "id", "issue_type", "created_at", "updated_at", "created_by", "updated_by", "deleted_at" ] + def validate(self, data): + data['issue_type_id'] = self.context["issue_type_id"] + return data - def create(self, validated_data): - return IssueTypeCustomProperty.objects.create( - **validated_data, - issue_type_id=self.context["issue_type_id"] - )apiserver/plane/settings/storage.py (1)
91-91: Remove unnecessary blank linesThere are unnecessary blank lines added at lines 91 and 100 that don't serve any functional purpose.
try: - # Generate a presigned URL for the S3 object response = self.s3_client.generate_presigned_post( Bucket=self.aws_storage_bucket_name, Key=object_name, Fields=fields, Conditions=conditions, ExpiresIn=expiration, ) -Also applies to: 100-100
web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx (1)
267-267: Remove commented codeThere's a commented implementation of the handleUpdate prop. Remove unnecessary commented code to keep the codebase clean.
- // handleUpdate={(val) => handleFiltersUpdate("custom_properties", null, val)}apiserver/plane/middleware/api_log_middleware.py (2)
22-32: Remove or implement commented codeThis commented-out method doesn't serve any purpose as is. Either implement it or remove it completely to avoid confusion.
- # def process_view(self, request, view_func, view_args, view_kwargs): - # path_split = request.path.split('/') - # print(len(path_split)) - # if len(path_split) <= 6: - # return request.path - # if request.path.split('/')[6] == 'DEFAULT': - # path_parts = request.path.split('/') - # view_kwargs['project_id'] = '9f54ba83-aa85-43ce-9ce6-b2968f066e85' - # - - return request.path
33-44: Clean up or implement project_rewiter methodThe
project_rewitermethod contains commented-out code and currently just returns the original path without any modifications. Either implement the intended functionality or simplify the method.def project_rewiter(self, request): - # Modify `kwargs` as needed - # path_split = request.path.split('/') - # print(len(path_split)) - # if len(path_split) <= 6: - # return request.path - # if request.path.split('/')[6] == 'DEFAULT': - # path_parts = request.path.split('/') - # path_parts[6] = 'dab178af-a6bb-4bfb-a0a8-ae8fd702b587' - # return '/'.join(path_parts) - return request.path - -apiserver/plane/api/urls/issue_type.py (1)
10-18: Consider using distinct URL names for different routes.Both URL patterns on lines 10-13 and 14-18 use the same name "issue-type", which could cause conflicts when using Django's URL reversing functions like
reverse()or the{% url %}template tag. This may lead to unpredictable behavior when generating URLs in your application.Consider using more specific names like "issue-type-list" for the first pattern and "issue-type-detail" for the second pattern.
path( "workspaces/<str:slug>/issue-type/", IssueTypeAPIEndpoint.as_view(), - name="issue-type", + name="issue-type-list", ), path( "workspaces/<str:slug>/issue-type/<uuid:pk>/", IssueTypeAPIEndpoint.as_view(), - name="issue-type", + name="issue-type-detail", ),apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py (1)
27-27: Consider more consistent related_name.The related_name "custom_propery_issue_type" contains a typo ("propery" instead of "property"). Additionally, it would be more consistent to use the same pattern as other related_names in the model.
- ('issue_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_propery_issue_type', to='db.issuetype')), + ('issue_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_property_issue_type', to='db.issuetype')),docker-compose-local.yml (1)
198-198: Remove unused volume.The
rabbitmq_datavolume is still defined but no service is using it after the removal of theplane-mqservice. Consider removing this unused volume definition to keep the docker-compose file clean.volumes: redisdata: uploads: pgdata: - rabbitmq_data:apiserver/plane/api/middleware/api_authentication.py (1)
54-56: Remove debug code and fix typo in method name.The method
rewite_project_id_in_urlhas a typo (should be "rewrite") and contains a commented-out debugging statement. Remove the debugging code and fix the method name for production code.- def rewite_project_id_in_url(self): + def rewrite_project_id_in_url(self): pass - # import pdb;pdb.set_trace()apiserver/plane/settings/common.py (1)
33-35: Consider using a more specific .env filename.The current code loads from "file.env" which is an unusual name. Consider using a more standard name like ".env" or something more descriptive that indicates the environment (e.g., "local.env", "development.env").
-print(f"BASE_DIR: {BASE_DIR}") -load_dotenv(os.path.join(BASE_DIR, "file.env")) +load_dotenv(os.path.join(BASE_DIR, ".env"))apiserver/plane/api/views/__init__.py (1)
37-42: Unused imports detected.Static analysis indicates that many of the imports in this file are unused. If these are intended for re-export, consider adding them to an
__all__list or creating a more explicit re-export pattern.+__all__ = [ + "ProjectAPIEndpoint", + "ProjectArchiveUnarchiveAPIEndpoint", + "StateAPIEndpoint", + "WorkspaceIssueAPIEndpoint", + "IssueAPIEndpoint", + "LabelAPIEndpoint", + "IssueLinkAPIEndpoint", + "IssueCommentAPIEndpoint", + "IssueActivityAPIEndpoint", + "IssueAttachmentEndpoint", + "IssueCustomPropertyUpdateAPIView", + "IssueTypeAPIEndpoint", + "IssueTypeCustomPropertyAPIEndpoint", + "IssueAttachmentV2Endpoint", + "CycleAPIEndpoint", + "CycleIssueAPIEndpoint", + "TransferCycleIssueAPIEndpoint", + "CycleArchiveUnarchiveAPIEndpoint", + "ModuleAPIEndpoint", + "ModuleIssueAPIEndpoint", + "ModuleArchiveUnarchiveAPIEndpoint", + "ProjectMemberAPIEndpoint", + "InboxIssueAPIEndpoint", + "GlobalSearchEndpoint", + "WebhookEndpoint", + "WebhookLogsEndpoint", + "WebhookSecretRegenerateEndpoint", +]🧰 Tools
🪛 Ruff (0.8.2)
37-37:
.search.GlobalSearchEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
40-40:
.webhook.WebhookEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
40-40:
.webhook.WebhookLogsEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
41-41:
.webhook.WebhookSecretRegenerateEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
web/core/components/issues/issue-detail/issue-activity/activity/actions/custom-properties.tsx (3)
14-29: Consider adding type safety for property values.The values
newValueandoldValueare directly displayed in the UI without type validation. They should be properly typed and potentially formatted based on the type of custom property (date, number, string, etc.).- const newValue = activity.new_value; - const oldValue = activity.old_value; + const newValue = activity.new_value !== null ? String(activity.new_value) : ''; + const oldValue = activity.old_value !== null ? String(activity.old_value) : '';
36-42: Remove unnecessary Fragment wrapper.The Fragment wrapper (
<>...</>) on line 36 is unnecessary since it only contains one child element.- <> {isNewProperty ? ( <>Added a Custom Property <span className="font-medium text-custom-text-100">{customPropertyKey}</span> with value <span className="font-medium text-custom-text-100">{newValue}</span>.</> ) : ( <>Updated the value of <span className="font-medium text-custom-text-100">{customPropertyKey}</span> from <span className="font-medium text-custom-text-100">{oldValue}</span> to <span className="font-medium text-custom-text-100">{newValue}</span>.</> )} - </>🧰 Tools
🪛 Biome (1.9.4)
[error] 36-42: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
30-45: Implement accessibility improvements for the component.The component could be improved with screen reader accessibility by using semantic elements or ARIA roles.
return ( <IssueActivityBlockComponent icon={<DoubleCircleIcon className="h-4 w-4 flex-shrink-0 text-custom-text-200" />} activityId={activityId} ends={ends} > - <> {isNewProperty ? ( - <>Added a Custom Property <span className="font-medium text-custom-text-100">{customPropertyKey}</span> with value <span className="font-medium text-custom-text-100">{newValue}</span>.</> + <p aria-label={`Added custom property ${customPropertyKey} with value ${newValue}`}> + Added a Custom Property <span className="font-medium text-custom-text-100">{customPropertyKey}</span> with value <span className="font-medium text-custom-text-100">{newValue}</span>. + </p> ) : ( - <>Updated the value of <span className="font-medium text-custom-text-100">{customPropertyKey}</span> from <span className="font-medium text-custom-text-100">{oldValue}</span> to <span className="font-medium text-custom-text-100">{newValue}</span>.</> + <p aria-label={`Updated custom property ${customPropertyKey} from ${oldValue} to ${newValue}`}> + Updated the value of <span className="font-medium text-custom-text-100">{customPropertyKey}</span> from <span className="font-medium text-custom-text-100">{oldValue}</span> to <span className="font-medium text-custom-text-100">{newValue}</span>. + </p> )} - </> </IssueActivityBlockComponent> );🧰 Tools
🪛 Biome (1.9.4)
[error] 36-42: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment(lint/complexity/noUselessFragments)
apiserver/plane/app/permissions/project.py (3)
49-49: Avoid raw print statements in production code.Consider using a logger (e.g., Python’s built-in
loggingmodule) instead of a
53-54: Consistent superuser bypass.This check repeats the same superuser bypass logic. If you rely on the same pattern in multiple places, consider factoring it into a common base permission method to reduce duplication.
159-161: Repeated superuser bypass check.These lines mirror the same pattern above. As previously noted, consider standardizing or verifying consistency across all permission classes.
apiserver/plane/api/views/issue_type.py (3)
1-26: Remove unused imports.Static analysis indicates that several imports like
Case,CharField,Exists,F,Func,Max,OuterRef,Q,Value,When,Subquery,MultiPartParser,FormParser, andissue_activity(line 35) are unused. Removing them will keep the codebase clean and reduce confusion.- from django.db.models import ( - Case, - CharField, - Exists, - F, - Func, - Max, - OuterRef, - Q, - Value, - When, - Subquery, - ) - from rest_framework.parsers import MultiPartParser, FormParser - from plane.bgtasks.issue_activities_task import issue_activity🧰 Tools
🪛 Ruff (0.8.2)
8-8:
django.db.models.Caseimported but unusedRemove unused import
(F401)
9-9:
django.db.models.CharFieldimported but unusedRemove unused import
(F401)
10-10:
django.db.models.Existsimported but unusedRemove unused import
(F401)
11-11:
django.db.models.Fimported but unusedRemove unused import
(F401)
12-12:
django.db.models.Funcimported but unusedRemove unused import
(F401)
13-13:
django.db.models.Maximported but unusedRemove unused import
(F401)
14-14:
django.db.models.OuterRefimported but unusedRemove unused import
(F401)
15-15:
django.db.models.Qimported but unusedRemove unused import
(F401)
16-16:
django.db.models.Valueimported but unusedRemove unused import
(F401)
17-17:
django.db.models.Whenimported but unusedRemove unused import
(F401)
18-18:
django.db.models.Subqueryimported but unusedRemove unused import
(F401)
25-25:
rest_framework.parsers.MultiPartParserimported but unusedRemove unused import
(F401)
25-25:
rest_framework.parsers.FormParserimported but unusedRemove unused import
(F401)
43-86: Check theIssueTypeAPIEndpoint.getlogic for performance.This method retrieves either a specific record or paginated results. Make sure you have appropriate indexing (e.g., on
workspace__slug) to optimize lookups for large data sets.
198-240: Validate use ofWorkspaceobject inIssueTypeCustomPropertyAPIEndpoint.You assign
workspace(line 200) but never use it. Also, watch out for theValidationErrorreference at line 236 ifdjango.core.exceptions.ValidationErroris not already imported or spelled differently. Ensure you’re referencing the right object or remove unused variables.🧰 Tools
🪛 Ruff (0.8.2)
200-200: Local variable
workspaceis assigned to but never usedRemove assignment to unused variable
workspace(F841)
236-236: Undefined name
ValidationError(F821)
apiserver/plane/api/views/base.py (4)
78-78: Use logging library instead of print.Printing exceptions is generally not recommended for production. Consider using structured logging with error levels.
89-89: Avoid multiple statements on one line.Static analysis flags the semicolon usage. For clarity and maintainability, split the import and traceback calls onto separate lines, or remove the semicolon:
- import traceback; traceback.print_exc() + import traceback + traceback.print_exc()🧰 Tools
🪛 Ruff (0.8.2)
89-89: Multiple statements on one line (semicolon)
(E702)
129-144: Ensurecheck_kwargsusage does not introduce hidden dependencies.This method calls
MagicSignInEndpointto mutate data ifslugis present. If that’s intended, confirm no duplication with your normal authentication flow, and handle any failures or partial updates.
145-164: Review user creation logic inget_or_create_user_from_headers.This approach automatically creates a user if
X-Assume-Roleis set and the user does not exist. Ensure you handle use cases around security, default password assignment, or user duplication properly.apiserver/plane/app/views/view/base.py (2)
3-3: Remove unused import.The import
Countfromdjango.db.modelsis not used anywhere in this file.-from django.db.models import Count🧰 Tools
🪛 Ruff (0.8.2)
3-3:
django.db.models.Countimported but unusedRemove unused import:
django.db.models.Count(F401)
314-328: Consider optimizing property grouping.The property grouping implementation could be optimized. You're retrieving all properties, serializing them, then looping through them to build a grouped dictionary.
Consider using Django's annotation/aggregation features to group properties at the database level.
def listCustomProperty(self, request, slug): customPropertyAllowedKeys = ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAP.get(slug, []) - custom_properties = IssueCustomProperty.objects.filter(key__in=customPropertyAllowedKeys) - serializer = IssueCustomPropertySerializer(custom_properties, many=True) - - groupedCustomProperties = {} - for item in serializer.data: - key = item.get("key") - value = item.get("value") - if value is None or key not in customPropertyAllowedKeys: - continue - groupedCustomProperties.setdefault(key, set()).add(value) - - groupedUniqueCustomProperties = {key: list(values) for key, values in groupedCustomProperties.items()} + # Group at database level to reduce memory usage + from django.db.models import Func, F, Value + from django.contrib.postgres.aggregates import ArrayAgg + + grouped_properties = ( + IssueCustomProperty.objects + .filter(key__in=customPropertyAllowedKeys, value__isnull=False) + .values('key') + .annotate(values=ArrayAgg('value', distinct=True)) + ) + + groupedUniqueCustomProperties = {item['key']: item['values'] for item in grouped_properties} return Response(groupedUniqueCustomProperties, status=status.HTTP_200_OK)web/core/services/workspace.service.ts (1)
292-300: Use more specific types instead of 'any'.The
fieldparameter is typed asany, which reduces TypeScript's ability to provide type checking. Consider using a more specific type.- async getIssueAdditionalProperties(workspaceSlug: string, projectId: string , field: any): Promise<any> { + async getIssueAdditionalProperties(workspaceSlug: string, projectId: string , field: string): Promise<Record<string, unknown>> {apiserver/plane/authentication/provider/credentials/magic_code.py (1)
131-133: Remove debug print statements.These debugging print statements should be removed before merging to production.
- keys = ri.keys('*') - print("All keys in redis:", keys) - print("Key to be checked:", self.key)apiserver/plane/api/urls/issue.py (1)
80-89: Inconsistent URL structure for custom properties endpointsThe newly added custom properties endpoints follow a different URL structure than the other issue-related endpoints. While most endpoints include
projects/<str:project_id>, these new ones skip the project level and go directly from workspace to issue.This inconsistency might cause confusion for API users and could make future maintenance more difficult.
Consider aligning the URL structure with existing patterns:
- path( - 'workspaces/<str:slug>/issues/<uuid:issue_id>/custom-properties/<uuid:pk>/', - IssueCustomPropertyUpdateAPIView.as_view(), - name="update-issue-custom-property", - ), - path( - 'workspaces/<str:slug>/issues/<uuid:issue_id>/custom-properties/', - IssueCustomPropertyUpdateAPIView.as_view(), - name="create-issue-custom-property", - ), + path( + 'workspaces/<str:slug>/projects/<str:project_id>/issues/<uuid:issue_id>/custom-properties/<uuid:pk>/', + IssueCustomPropertyUpdateAPIView.as_view(), + name="update-issue-custom-property", + ), + path( + 'workspaces/<str:slug>/projects/<str:project_id>/issues/<uuid:issue_id>/custom-properties/', + IssueCustomPropertyUpdateAPIView.as_view(), + name="create-issue-custom-property", + ),apiserver/plane/api/views/project.py (1)
242-242: Extra blank lineThere's an extra blank line at line 242 which can be removed for consistency.
web/core/constants/issue.ts (2)
113-124: Potential typo in variable nameThe variable
whileListedCustomPropertiesappears to have a typo. Did you meanwhiteListedCustomProperties?-const whileListedCustomProperties = [ +const whiteListedCustomProperties = [ { key: "trip_reference_number", title: "Trip Reference Number" }, { key: "reference_number", title: "Reference Number" }, ... ];
535-549: Duplicated property definitionsThe
ISSUE_ADDITIONAL_PROPERTIESarray contains largely the same properties aswhileListedCustomPropertiesdefined earlier in the file. This duplication could lead to maintenance issues if they need to be updated separately.Consider reusing the existing definitions instead of duplicating them:
-export const ISSUE_ADDITIONAL_PROPERTIES: { - key: keyof TIssue; - title: string; - }[] = [ - { key: "trip_reference_number", title: "Trip Ref Number" }, - { key: "reference_number", title: "Reference Number" }, - { key: "hub_code", title: "Hub Code" }, - { key: "hub_name", title: "Hub Name" }, - { key: "customer_code", title: "Customer Code" }, - { key: "customer_name", title: "Customer Name" }, - { key: "vendor_code", title: "Vendor Code" }, - { key: "vendor_name", title: "Vendor Name" }, - { key: "worker_code", title: "Worker Code" }, - { key: "worker_name", title: "Worker Name" } - ]; +export const ISSUE_ADDITIONAL_PROPERTIES: { + key: keyof TIssue; + title: string; + }[] = whiteListedCustomProperties.map(prop => ({ + key: prop.key, + title: prop.key === "trip_reference_number" ? "Trip Ref Number" : prop.title + }));Note: If you need to maintain different titles or properties, consider creating a base set of properties that both arrays can reference and extend.
packages/types/src/issues/issue.d.ts (1)
72-72: Consider the implications of using an index signature.Adding
[key: string]: anyallows for any property to be added toTIssueobjects. While this provides flexibility, it also reduces type safety and could lead to runtime errors if properties are accessed incorrectly.If you only need the specific new properties, consider removing this index signature and explicitly defining all needed properties instead.
apiserver/plane/api/views/member.py (3)
125-135: Profile setup could benefit from error handling.While the profile setup code looks good functionally, consider adding error handling for the profile creation and update operations to ensure robustness.
if not user: user = self.create_user(user_data) - profile, _ = Profile.objects.get_or_create(user=user) - profile.last_workspace_id = workspace.id - profile.onboarding_step.update({ - 'profile_complete': True, - 'workspace_join': True - }) - profile.is_tour_completed = True - profile.is_onboarded = True - profile.company_name = workspace.name - profile.save() + try: + profile, _ = Profile.objects.get_or_create(user=user) + profile.last_workspace_id = workspace.id + profile.onboarding_step.update({ + 'profile_complete': True, + 'workspace_join': True + }) + profile.is_tour_completed = True + profile.is_onboarded = True + profile.company_name = workspace.name + profile.save() + except Exception as e: + # Log the error but continue execution + print(f"Error setting up user profile: {e}")
165-172: Redundant save call in workspace member creation.The
create_workspace_membermethod has a redundantsave()call sinceWorkspaceMember.objects.create()already saves the object.def create_workspace_member(self, workspace_id, user, role=15): workspace_member = WorkspaceMember.objects.create( workspace_id=workspace_id, member=user, role=role ) - workspace_member.save()
173-180: Redundant save call in project member creation.The
create_project_membermethod has a redundantsave()call sinceProjectMember.objects.create()already saves the object.def create_project_member(self, project_id, user, role=15): # Create a project member for the user if not already a member project_member = ProjectMember.objects.create( project_id=project_id, member=user, role=role ) - project_member.save()apiserver/Dockerfile.api (1)
67-77: Comprehensive CMD instruction for different environment types.The CMD instruction now handles different environment types effectively, allowing for different behavior based on the deployment scenario. However, there's a small typo in the Flower URL prefix parameter.
elif [ "${ENV_TYPE}" = "celery-beat" ]; then \ - (celery -A plane flower --port=5555 --address=0.0.0.0 --url-prefix=flower &) && celery -A plane beat -l info; \ + (celery -A plane flower --port=5555 --address=0.0.0.0 --url_prefix=flower &) && celery -A plane beat -l info; \Note that in the "celery" environment type, you're using
--url_prefixbut in the "celery-beat" environment, you're using--url-prefix. They should be consistent.web/core/components/issues/issue-layouts/filters/header/filters/additional-properties.tsx (2)
27-39: API fetch with potential improvements.The API fetch logic could be improved with a loading state, better error handling, and prevention of unnecessary API calls when the component unmounts.
const [options, setOptions] = useState<{ label: string; value: string }[]>([]); const [previewEnabled, setPreviewEnabled] = useState(true); const [visibleOptions, setVisibleOptions] = useState(5); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState<string | null>(null); useEffect(() => { const fetchOptions = async () => { + if (!workspaceSlug || !projectId || !additionalPropertyKey) return; + + setIsLoading(true); + setError(null); try { const response = await workspaceService.getIssueAdditionalProperties(workspaceSlug.toString(), projectId.toString(), props.additionalPropertyKey); const formattedOptions = response.data.map((item: string) => ({ label: item, value: item })) || []; setOptions(formattedOptions); } catch (error) { console.error(`Error fetching ${additionalPropertyKey} options:`, error); + setError(`Failed to load ${additionalPropertyTitle || additionalPropertyKey} options`); + } finally { + setIsLoading(false); } }; + let isMounted = true; + if (isMounted) { fetchOptions(); + } + + return () => { + isMounted = false; + }; }, [workspaceSlug, projectId, additionalPropertyKey]);
45-79: Render loading and error states in the component.The component should display loading and error states to improve user experience.
return ( <> <FilterHeader title={`${additionalPropertyTitle} ${appliedFilters?.length ? `(${appliedFilters.length})` : ""}`} isPreviewEnabled={previewEnabled} handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} /> {previewEnabled && ( <div> + {isLoading && ( + <p className="text-xs text-custom-text-400">Loading...</p> + )} + {error && ( + <p className="text-xs text-red-500">{error}</p> + )} - {filteredOptions.length > 0 ? ( + {!isLoading && !error && filteredOptions.length > 0 ? ( <> {filteredOptions.slice(0, visibleOptions).map(({ label, value }) => ( <FilterOption key={value} isChecked={appliedFilters?.includes(value) ?? false} onClick={() => handleUpdate(value)} title={label} /> ))} {filteredOptions.length > 5 && ( <button className="text-blue-500 text-xs mt-2" onClick={() => setVisibleOptions(visibleOptions === 5 ? filteredOptions.length : 5)} > {visibleOptions === 5 ? "View More" : "View Less"} </button> )} </> - ) : ( + ) : (!isLoading && !error) ? ( <p className="text-xs italic text-custom-text-400">No Matches Found</p> + ) : ( + null )} </div> )} </> );web/core/constants/spreadsheet.ts (1)
181-270: Extensive duplication in property definitions.The new property definitions contain significant duplication that could be reduced with a more programmatic approach. Consider using a factory function to create these property objects.
+ // Define a factory function for creating standard property objects + const createStandardProperty = ( + key: string, + title: string + ) => ({ + title, + ascendingOrderKey: key, + ascendingOrderTitle: "A", + descendingOrderKey: `-${key}`, + descendingOrderTitle: "Z", + icon: Tags, + Column: SpreadsheetStandardPropertyColumn, + }); + + // Create property objects using the factory function + const standardProperties = { + trip_reference_number: createStandardProperty("trip_reference_number", "Trip Ref Number"), + reference_number: createStandardProperty("reference_number", "Reference Number"), + hub_code: createStandardProperty("hub_code", "Hub Code"), + hub_name: createStandardProperty("hub_name", "Hub Name"), + customer_code: createStandardProperty("customer_code", "Customer Code"), + customer_name: createStandardProperty("customer_name", "Customer Name"), + vendor_name: createStandardProperty("vendor_name", "Vendor Name"), + vendor_code: createStandardProperty("vendor_code", "Vendor Code"), + worker_code: createStandardProperty("worker_code", "Worker Code"), + worker_name: createStandardProperty("worker_name", "Worker Name"), + }; + + // Merge the standard properties with the existing SPREADSHEET_PROPERTY_DETAILS + export const SPREADSHEET_PROPERTY_DETAILS = { + // Existing properties... + ...standardProperties, + };This approach would significantly reduce code duplication while maintaining the same functionality.
web/core/components/issues/peek-overview/properties.tsx (1)
346-357: Refine type usage forprop.Using
anydilutes type safety. Define a proper interface or type to ensure clarity and maintainability.- {ISSUE_ADDITIONAL_PROPERTIES.map((prop: any) => + {ISSUE_ADDITIONAL_PROPERTIES.map((prop: { key: keyof TIssue; title: string }) =>web/core/components/issues/issue-layouts/filters/header/filters/custom-properties.tsx (1)
119-125: Simplify the ternary expression forisChecked.You can directly pass the boolean evaluation without explicitly using
? true : false.- isChecked={appliedFilters?.includes(`${groupKey}:${property}`) ? true : false} + isChecked={appliedFilters?.includes(`${groupKey}:${property}`)}🧰 Tools
🪛 Biome (1.9.4)
[error] 121-121: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with(lint/complexity/noUselessTernary)
apiserver/plane/utils/issue_filters.py (3)
6-6: Remove unused import.
Qis imported but not used in the final code.- from django.db.models import Q🧰 Tools
🪛 Ruff (0.8.2)
6-6:
django.db.models.Qimported but unusedRemove unused import:
django.db.models.Q(F401)
271-271: Remove or replace debug print.Leaving debug statements in production code can clutter logs.
- print(created_bys) + # print(created_bys) # Remove or replace with logging if necessary
590-590: Remove or replace debug print infilter_custom_properties.Helps maintain a cleaner log output.
- print(issue_filter) + # print(issue_filter) // or use a logger if requiredapiserver/plane/app/views/issue/base.py (3)
60-60: Remove unused import.
ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAPis never used.- from plane.utils.constants import ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAP🧰 Tools
🪛 Ruff (0.8.2)
60-60:
plane.utils.constants.ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAPimported but unusedRemove unused import:
plane.utils.constants.ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAP(F401)
72-74: Remove unused permission imports.These are not referenced in the file.
- ProjectEntityPermission, - ProjectLitePermission, - ProjectMemberPermission,🧰 Tools
🪛 Ruff (0.8.2)
72-72:
plane.app.permissions.ProjectEntityPermissionimported but unusedRemove unused import
(F401)
73-73:
plane.app.permissions.ProjectLitePermissionimported but unusedRemove unused import
(F401)
74-74:
plane.app.permissions.ProjectMemberPermissionimported but unusedRemove unused import
(F401)
438-438: Eliminate or guard debug print statements.Multiple
- print(serializer.data) - print(issue) - print(serializer.data) + # print(serializer.data) + # print(issue) + # ...Also applies to: 503-503, 670-670
web/core/components/issues/custom-properties.tsx (2)
58-70: Consider aligning the naming convention between server response and local properties.The code uses
customProp.namefrom the server response and maps it tokeyin the local object, while also using local objects keyed byprop.key. This can be confusing when debugging. Unifying the naming (e.g., renamingnametokeyserver-side or vice versa) could improve clarity and reduce confusion around property matching.
80-99: Double-check error handling forupdateCustomPropertiescalls.Currently, when a custom property update fails, the error is logged to the console, but there's no user-facing feedback to indicate that the update was not saved. Consider adding in-component or global error notifications or retry logic to inform users of failures and allow them to address issues more gracefully.
apiserver/plane/api/serializers/issue.py (2)
36-41: Remove the unuseduuid_objassignment to address the static analysis warning.The variable
uuid_objis assigned inis_uuidbut never read. Simplify by removing this unused assignment:-def is_uuid(value): - try: - uuid_obj = uuid.UUID(str(value)) # Convert to string in case it's not already - return True - except (ValueError, TypeError): - return False +def is_uuid(value): + try: + uuid.UUID(str(value)) # Convert to string in case it's not already + return True + except (ValueError, TypeError): + return False🧰 Tools
🪛 Ruff (0.8.2)
38-38: Local variable
uuid_objis assigned to but never usedRemove assignment to unused variable
uuid_obj(F841)
160-176: Avoid printing sensitive data in production logs.There's a
print(data)statement that might expose confidential information. Silence or log it securely at an appropriate logging level if needed.apiserver/plane/db/models/issue.py (1)
146-155: Consider indexing frequently searched fields.You've introduced several new fields (
hub_code,vendor_code,customer_code, etc.). If you anticipate queries filtering by these fields, adding database indexes will improve query performance.apiserver/plane/bgtasks/issue_activities_task.py (4)
370-379: Enhance error handling for fallback logic intrack_assignees.The newly introduced fallback logic that checks both
"assignee_ids"and"assignees"is a good approach. However, consider improving error handling in case these fields contain invalid data or reference non-existent user IDs. You may also remove the extra blank line at line 372 to maintain consistency.
602-603: Fix inconsistent spacing and unify condition checks.Line 602 lacks a space before
is:requested_data.get("assignees")is not None. Also, consider simplifying the conditional logic to handle emptiness:-if requested_data.get("assignee_ids") is not None or requested_data.get("assignees")is not None: +if requested_data.get("assignee_ids") or requested_data.get("assignees"):Also applies to: 612-613
1613-1644: Consider robust JSON parsing and error handling.In
update_custom_property_activity, you convert string inputs to JSON without a try-except block. If eithercurrent_instanceorrequested_datais malformed, it can raise aJSONDecodeError. Consider adding error handling or validating JSON before parsing to avoid runtime issues.
1646-1676: Add protective fallback for custom property creation.In
create_custom_property_activity, it's good to see a default'unknown_key'. However, consider validating the key/value pair more thoroughly to avoid inconsistent or invalid data. Even a quick check or logging would help identify malformed requests more quickly.apiserver/plane/api/views/webhook.py (1)
18-39: Monitor the usage of410_GONE.While checking for duplications is correct, returning
HTTP_410_GONEwhen the URL already exists is uncommon—409_CONFLICTis more typical for duplicate resource conflicts.apiserver/plane/api/views/search.py (3)
37-48: Optionally includeworkspace_member__is_activecheck.Filtering workspaces by
workspace_member__member=self.request.useris good, but consider verifying that the membership is active to avoid pulling in inactive or deleted memberships.
68-106: Regex-based sequence ID matching may raise performance concerns.Using
re.findall(r"\b\d+\b", query)is flexible but can be expensive for large queries. Consider bounding your search or optimizing this logic for better performance.
132-156: Check for module-level archiving.While you exclude archived projects, confirm whether
Modulealso needs anarchived_atcheck for consistency if such a field exists.demo.Jenkinsfile (1)
33-35: Use versioned Docker images for a robust deployment strategy.Instead of tagging images with
latest, consider employing semantic versioning or commit-based tags to ensure reproducible builds, ease rollbacks, and maintain better traceability.-def webImageName = "plane-frontend:latest" -def adminImageName = "plane-adminpanel:latest" -def apiImageName = "plane-apiserver:latest" +def webImageName = "plane-frontend:${BUILD_TAG}" +def adminImageName = "plane-adminpanel:${BUILD_TAG}" +def apiImageName = "plane-apiserver:${BUILD_TAG}"apiserver/plane/api/views/issue.py (3)
37-37: Remove unused import.
IssueTypeSerializeris imported but not used anywhere. Removing it avoids confusion and meets linting standards.- IssueTypeSerializer,🧰 Tools
🪛 Ruff (0.8.2)
37-37:
plane.api.serializers.IssueTypeSerializerimported but unusedRemove unused import:
plane.api.serializers.IssueTypeSerializer(F401)
57-57: Remove unused import.
IssueTypeis imported fromplane.db.modelsbut is never referenced. Removing it keeps the code clean.- IssueType,🧰 Tools
🪛 Ruff (0.8.2)
57-57:
plane.db.models.IssueTypeimported but unusedRemove unused import:
plane.db.models.IssueType(F401)
156-156: Avoid leaving debug print statements.
print(query)might clutter logs in production. Consider replacing it with structured logging or removing it.-print(query) +# logger.debug("Issue query: %s", query)apiserver/plane/authentication/views/app/magic.py (1)
287-287: Remove unused variable.
is_appis assigned at line 287 but never used afterward. Remove it to maintain code clarity and pass lint checks.- is_app = request.POST.get("is_app", False)🧰 Tools
🪛 Ruff (0.8.2)
287-287: Local variable
is_appis assigned to but never usedRemove assignment to unused variable
is_app(F841)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (107)
admin/Dockerfile.admin(1 hunks)admin/ce/components/common/upgrade-button.tsx(1 hunks)admin/core/components/admin-sidebar/help-section.tsx(0 hunks)aio/nginx.conf(1 hunks)apiserver/Dockerfile.api(2 hunks)apiserver/plane/api/middleware/api_authentication.py(3 hunks)apiserver/plane/api/serializers/__init__.py(1 hunks)apiserver/plane/api/serializers/issue.py(11 hunks)apiserver/plane/api/serializers/issue_type.py(1 hunks)apiserver/plane/api/serializers/project.py(2 hunks)apiserver/plane/api/serializers/webhook.py(1 hunks)apiserver/plane/api/urls/__init__.py(2 hunks)apiserver/plane/api/urls/issue.py(2 hunks)apiserver/plane/api/urls/issue_type.py(1 hunks)apiserver/plane/api/urls/project.py(2 hunks)apiserver/plane/api/urls/search.py(1 hunks)apiserver/plane/api/urls/state.py(1 hunks)apiserver/plane/api/urls/webhook.py(1 hunks)apiserver/plane/api/views/__init__.py(3 hunks)apiserver/plane/api/views/attachment.py(1 hunks)apiserver/plane/api/views/base.py(6 hunks)apiserver/plane/api/views/issue.py(12 hunks)apiserver/plane/api/views/issue_type.py(1 hunks)apiserver/plane/api/views/member.py(4 hunks)apiserver/plane/api/views/project.py(3 hunks)apiserver/plane/api/views/search.py(1 hunks)apiserver/plane/api/views/state.py(1 hunks)apiserver/plane/api/views/webhook.py(1 hunks)apiserver/plane/app/permissions/__init__.py(1 hunks)apiserver/plane/app/permissions/project.py(7 hunks)apiserver/plane/app/serializers/issue.py(5 hunks)apiserver/plane/app/urls/issue.py(2 hunks)apiserver/plane/app/urls/views.py(1 hunks)apiserver/plane/app/views/__init__.py(1 hunks)apiserver/plane/app/views/base.py(1 hunks)apiserver/plane/app/views/issue/base.py(14 hunks)apiserver/plane/app/views/view/base.py(6 hunks)apiserver/plane/authentication/adapter/base.py(2 hunks)apiserver/plane/authentication/provider/credentials/magic_code.py(3 hunks)apiserver/plane/authentication/utils/redirection_path.py(1 hunks)apiserver/plane/authentication/views/app/magic.py(5 hunks)apiserver/plane/bgtasks/issue_activities_task.py(6 hunks)apiserver/plane/bgtasks/webhook_task.py(1 hunks)apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py(1 hunks)apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py(1 hunks)apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py(1 hunks)apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py(1 hunks)apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py(1 hunks)apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py(1 hunks)apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py(1 hunks)apiserver/plane/db/migrations/0091_issue_customer_code_issue_hub_code_and_more.py(1 hunks)apiserver/plane/db/models/__init__.py(3 hunks)apiserver/plane/db/models/base.py(1 hunks)apiserver/plane/db/models/issue.py(4 hunks)apiserver/plane/db/models/issue_type.py(1 hunks)apiserver/plane/middleware/api_log_middleware.py(2 hunks)apiserver/plane/settings/common.py(7 hunks)apiserver/plane/settings/redis.py(1 hunks)apiserver/plane/settings/storage.py(4 hunks)apiserver/plane/utils/constants.py(1 hunks)apiserver/plane/utils/grouper.py(1 hunks)apiserver/plane/utils/issue_filters.py(6 hunks)apiserver/requirements/base.txt(3 hunks)apiserver/supervisord.conf(1 hunks)apiserver/templates/emails/exports/analytics.html(1 hunks)demo.Jenkinsfile(1 hunks)deploy/selfhost/install.sh(1 hunks)docker-compose-local.yml(3 hunks)docker-compose.yml(1 hunks)nginx/nginx.conf.dev(1 hunks)nginx/nginx.conf.template(1 hunks)packages/types/src/issues/issue.d.ts(1 hunks)packages/types/src/view-props.d.ts(2 hunks)space/core/components/issues/filters/selection.tsx(1 hunks)space/next.config.js(1 hunks)web/Dockerfile.web(1 hunks)web/app/[workspaceSlug]/(projects)/header.tsx(1 hunks)web/app/provider.tsx(3 hunks)web/app/workspace-invitations/page.tsx(1 hunks)web/ce/constants/project/settings/features.tsx(1 hunks)web/core/components/issues/custom-properties.tsx(1 hunks)web/core/components/issues/index.ts(1 hunks)web/core/components/issues/issue-detail/issue-activity/activity/actions/custom-properties.tsx(1 hunks)web/core/components/issues/issue-detail/issue-activity/activity/actions/index.ts(1 hunks)web/core/components/issues/issue-detail/issue-activity/activity/activity-list.tsx(2 hunks)web/core/components/issues/issue-detail/sidebar.tsx(6 hunks)web/core/components/issues/issue-layouts/filters/applied-filters/additional-properties.tsx(1 hunks)web/core/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx(3 hunks)web/core/components/issues/issue-layouts/filters/applied-filters/index.ts(1 hunks)web/core/components/issues/issue-layouts/filters/header/filters/additional-properties.tsx(1 hunks)web/core/components/issues/issue-layouts/filters/header/filters/custom-properties.tsx(1 hunks)web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx(2 hunks)web/core/components/issues/issue-layouts/filters/header/filters/index.ts(1 hunks)web/core/components/issues/issue-layouts/spreadsheet/columns/index.ts(1 hunks)web/core/components/issues/issue-layouts/spreadsheet/columns/standard-property-column.tsx(1 hunks)web/core/components/issues/issue-layouts/spreadsheet/issue-column.tsx(1 hunks)web/core/components/issues/peek-overview/properties.tsx(6 hunks)web/core/components/workspace/sidebar/dropdown.tsx(1 hunks)web/core/components/workspace/sidebar/help-section.tsx(1 hunks)web/core/components/workspace/sidebar/projects-list-item.tsx(0 hunks)web/core/constants/analytics.ts(1 hunks)web/core/constants/dashboard.ts(1 hunks)web/core/constants/issue.ts(8 hunks)web/core/constants/spreadsheet.ts(4 hunks)web/core/hooks/use-group-dragndrop.ts(1 hunks)web/core/services/workspace.service.ts(1 hunks)web/core/store/issue/helpers/issue-filter-helper.store.ts(3 hunks)
⛔ Files not processed due to max files limit (3)
- web/core/store/issue/issue-details/issue.store.ts
- web/helpers/issue.helper.ts
- web/next.config.js
💤 Files with no reviewable changes (2)
- admin/core/components/admin-sidebar/help-section.tsx
- web/core/components/workspace/sidebar/projects-list-item.tsx
🧰 Additional context used
🧬 Code Definitions (42)
apiserver/plane/app/permissions/__init__.py (1)
apiserver/plane/app/permissions/project.py (1)
ProjectEntityGuestPermission(119-152)
apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py (4)
apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py (1)
Migration(6-22)apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
Migration(7-24)apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
Migration(7-19)apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (1)
Migration(6-18)
apiserver/plane/app/views/__init__.py (1)
apiserver/plane/app/views/issue/base.py (2)
SearchAPIEndpoint(1222-1263)SearchSingleValueAPI(1265-1300)
web/core/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx (1)
web/core/components/issues/issue-layouts/filters/applied-filters/additional-properties.tsx (1)
AppliedAdditionalPropertiesFilters(14-33)
web/core/components/issues/issue-detail/issue-activity/activity/activity-list.tsx (1)
web/core/components/issues/issue-detail/issue-activity/activity/actions/custom-properties.tsx (1)
IssueCustomPropertyActivity(14-45)
apiserver/plane/authentication/adapter/base.py (2)
apiserver/plane/api/views/issue.py (8)
get(102-125)get(168-313)get(663-681)get(744-768)get(891-909)get(1055-1086)get(1161-1166)get(1210-1221)apiserver/plane/api/views/member.py (1)
get(37-58)
apiserver/plane/api/urls/search.py (1)
apiserver/plane/api/views/search.py (1)
GlobalSearchEndpoint(29-274)
apiserver/plane/api/serializers/project.py (1)
apiserver/plane/api/serializers/issue_type.py (1)
IssueTypeSerializer(7-24)
apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (3)
apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
Migration(7-19)apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py (1)
Migration(6-18)apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (1)
Migration(6-18)
apiserver/plane/app/urls/views.py (1)
apiserver/plane/app/views/view/base.py (1)
WorkspaceViewIssuesViewSet(208-467)
apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py (5)
apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
Migration(7-24)apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
Migration(7-19)apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py (1)
Migration(9-48)apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py (1)
Migration(6-18)apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (1)
Migration(6-18)
apiserver/plane/api/serializers/__init__.py (3)
apiserver/plane/api/serializers/issue.py (1)
IssueCustomPropertySerializer(43-54)apiserver/plane/app/views/issue/base.py (1)
IssueCustomPropertySerializer(77-88)apiserver/plane/api/serializers/issue_type.py (2)
IssueTypeSerializer(7-24)IssueTypeCustomPropertySerializer(26-44)
web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx (4)
web/core/constants/issue.ts (1)
ISSUE_ADDITIONAL_PROPERTIES(535-549)web/core/components/issues/issue-layouts/filters/header/filters/additional-properties.tsx (1)
FilterAdditionalProperties(18-80)packages/types/src/view-props.d.ts (1)
IIssueFilterOptions(94-116)web/core/components/issues/issue-layouts/filters/header/filters/custom-properties.tsx (1)
FilterCustomProperty(19-142)
apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (3)
apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
Migration(7-24)apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
Migration(7-19)apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py (1)
Migration(6-18)
apiserver/plane/api/middleware/api_authentication.py (2)
apiserver/plane/api/views/issue.py (8)
get(102-125)get(168-313)get(663-681)get(744-768)get(891-909)get(1055-1086)get(1161-1166)get(1210-1221)apiserver/plane/api/views/project.py (1)
get(202-240)
apiserver/plane/app/urls/issue.py (1)
apiserver/plane/app/views/issue/base.py (2)
SearchAPIEndpoint(1222-1263)SearchSingleValueAPI(1265-1300)
apiserver/plane/app/permissions/project.py (3)
apiserver/plane/api/views/base.py (2)
project_id(199-208)workspace_slug(195-196)apiserver/plane/db/models/project.py (1)
ProjectMember(215-259)apiserver/plane/api/views/issue.py (1)
project__identifier(78-79)
apiserver/plane/api/views/issue_type.py (3)
apiserver/plane/api/serializers/issue_type.py (2)
IssueTypeSerializer(7-24)IssueTypeCustomPropertySerializer(26-44)apiserver/plane/app/permissions/project.py (1)
ProjectLitePermission(155-168)apiserver/plane/db/models/issue_type.py (2)
IssueType(10-32)IssueTypeCustomProperty(62-84)
apiserver/plane/app/views/view/base.py (3)
apiserver/plane/db/models/issue.py (1)
IssueCustomProperty(734-755)apiserver/plane/utils/issue_filters.py (1)
issue_filters(622-661)apiserver/plane/app/views/base.py (2)
fields(148-154)fields(253-259)
apiserver/plane/authentication/provider/credentials/magic_code.py (1)
apiserver/plane/authentication/adapter/base.py (1)
set_user_data(44-45)
apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py (5)
apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py (1)
Migration(6-22)apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
Migration(7-24)apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
Migration(7-19)apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py (1)
Migration(6-18)apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (1)
Migration(6-18)
apiserver/plane/db/models/__init__.py (2)
apiserver/plane/db/models/issue.py (1)
IssueCustomProperty(734-755)apiserver/plane/db/models/issue_type.py (2)
IssueType(10-32)IssueTypeCustomProperty(62-84)
apiserver/plane/api/views/__init__.py (5)
apiserver/plane/api/views/project.py (2)
ProjectAPIEndpoint(124-377)ProjectArchiveUnarchiveAPIEndpoint(380-400)apiserver/plane/api/views/issue_type.py (1)
IssueTypeAPIEndpoint(43-196)apiserver/plane/api/views/attachment.py (1)
IssueAttachmentV2Endpoint(18-174)apiserver/plane/api/views/search.py (1)
GlobalSearchEndpoint(29-274)apiserver/plane/api/views/webhook.py (3)
WebhookEndpoint(16-107)WebhookLogsEndpoint(121-129)WebhookSecretRegenerateEndpoint(110-118)
apiserver/plane/api/views/project.py (1)
apiserver/plane/api/serializers/project.py (1)
create(66-88)
web/core/constants/issue.ts (1)
packages/types/src/issues/issue.d.ts (1)
TIssue(52-73)
web/core/components/issues/issue-layouts/filters/header/filters/additional-properties.tsx (1)
web/core/services/workspace.service.ts (1)
WorkspaceService(20-301)
web/core/constants/spreadsheet.ts (1)
web/core/components/issues/issue-layouts/spreadsheet/columns/standard-property-column.tsx (1)
SpreadsheetStandardPropertyColumn(12-22)
apiserver/plane/api/urls/state.py (1)
apiserver/plane/api/views/state.py (1)
StateAPIEndpoint(16-162)
apiserver/plane/api/urls/issue_type.py (1)
apiserver/plane/api/views/issue_type.py (2)
IssueTypeAPIEndpoint(43-196)IssueTypeCustomPropertyAPIEndpoint(198-240)
web/core/components/issues/issue-detail/sidebar.tsx (2)
web/core/components/issues/custom-properties.tsx (2)
CustomProperty(5-10)CustomProperties(20-192)web/core/constants/issue.ts (1)
ISSUE_ADDITIONAL_PROPERTIES(535-549)
apiserver/plane/app/views/issue/base.py (2)
apiserver/plane/app/permissions/project.py (3)
ProjectEntityPermission(83-116)ProjectLitePermission(155-168)ProjectMemberPermission(47-80)apiserver/plane/api/serializers/issue.py (1)
IssueCustomPropertySerializer(43-54)
web/core/components/issues/peek-overview/properties.tsx (2)
web/core/components/issues/custom-properties.tsx (2)
CustomProperty(5-10)CustomProperties(20-192)web/core/constants/issue.ts (1)
ISSUE_ADDITIONAL_PROPERTIES(535-549)
apiserver/plane/api/views/search.py (2)
apiserver/plane/api/views/base.py (3)
fields(211-217)BaseAPIView(40-226)project_id(199-208)apiserver/plane/db/models/issue.py (1)
Issue(112-276)
apiserver/plane/app/serializers/issue.py (3)
apiserver/plane/db/models/issue.py (17)
IssueCustomProperty(734-755)Meta(198-202)Meta(287-291)Meta(319-331)Meta(347-359)Meta(375-387)Meta(401-405)Meta(435-439)Meta(485-489)Meta(530-534)Meta(553-565)Meta(580-584)Meta(600-604)Meta(617-629)Meta(646-658)Meta(677-689)Meta(712-728)apiserver/plane/app/views/issue/base.py (1)
IssueCustomPropertySerializer(77-88)apiserver/plane/api/serializers/issue.py (1)
IssueCustomPropertySerializer(43-54)
apiserver/plane/api/views/webhook.py (2)
apiserver/plane/app/views/base.py (3)
BaseAPIView(166-268)fields(148-154)fields(253-259)apiserver/plane/api/serializers/webhook.py (2)
WebhookSerializer(15-128)WebhookLogSerializer(131-135)
apiserver/plane/api/views/attachment.py (3)
apiserver/plane/api/serializers/issue.py (3)
IssueAttachmentSerializer(445-457)create(181-268)create(419-427)apiserver/plane/settings/storage.py (3)
S3Storage(14-166)generate_presigned_post(66-106)generate_presigned_url(116-144)apiserver/plane/db/models/base.py (1)
save(25-42)
apiserver/plane/api/views/base.py (4)
apiserver/plane/db/models/project.py (1)
Project(53-176)apiserver/plane/authentication/views/app/magic.py (2)
MagicSignInEndpoint(88-272)add_user_to_workspace(95-101)apiserver/plane/api/views/search.py (1)
get(236-274)apiserver/plane/api/views/member.py (1)
get(37-58)
apiserver/plane/api/views/issue.py (1)
apiserver/plane/api/serializers/issue.py (4)
IssueCustomPropertySerializer(43-54)IssueSerializer(56-359)create(181-268)create(419-427)
apiserver/plane/api/serializers/issue.py (3)
apiserver/plane/db/models/issue.py (17)
IssueCustomProperty(734-755)Meta(198-202)Meta(287-291)Meta(319-331)Meta(347-359)Meta(375-387)Meta(401-405)Meta(435-439)Meta(485-489)Meta(530-534)Meta(553-565)Meta(580-584)Meta(600-604)Meta(617-629)Meta(646-658)Meta(677-689)Meta(712-728)apiserver/plane/api/views/member.py (4)
ProjectMemberAPIEndpoint(31-180)create_user(150-164)create_workspace_member(165-171)create_project_member(173-180)apiserver/plane/api/serializers/issue_type.py (1)
create(40-44)
web/core/components/issues/issue-layouts/filters/header/filters/custom-properties.tsx (1)
web/core/services/workspace.service.ts (1)
WorkspaceService(20-301)
apiserver/plane/api/urls/issue.py (3)
apiserver/plane/api/views/attachment.py (1)
IssueAttachmentV2Endpoint(18-174)apiserver/plane/api/views/issue_type.py (1)
IssueTypeAPIEndpoint(43-196)apiserver/plane/api/views/issue.py (2)
IssueCustomPropertyUpdateAPIView(1168-1277)IssueAPIEndpoint(127-582)
apiserver/plane/authentication/views/app/magic.py (3)
apiserver/plane/api/serializers/project.py (2)
ProjectSerializer(15-88)create(66-88)apiserver/plane/api/views/base.py (1)
BaseAPIView(40-226)apiserver/plane/api/views/project.py (1)
create_project(34-122)
🪛 Ruff (0.8.2)
apiserver/plane/app/permissions/__init__.py
14-14: .project.ProjectEntityGuestPermission imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
apiserver/plane/app/views/__init__.py
135-135: .issue.base.SearchAPIEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
136-136: .issue.base.SearchSingleValueAPI imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
apiserver/plane/api/serializers/project.py
12-12: .issue_type.IssueTypeSerializer imported but unused
Remove unused import: .issue_type.IssueTypeSerializer
(F401)
apiserver/plane/api/serializers/__init__.py
13-13: .issue.IssueCustomPropertySerializer imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
15-15: .issue_type.IssueTypeSerializer imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
15-15: .issue_type.IssueTypeCustomPropertySerializer imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
apiserver/plane/api/serializers/issue_type.py
1-1: rest_framework.serializers imported but unused
Remove unused import: rest_framework.serializers
(F401)
apiserver/plane/bgtasks/webhook_task.py
407-407: Local variable event_data is assigned to but never used
Remove assignment to unused variable event_data
(F841)
408-408: Local variable actor_data is assigned to but never used
Remove assignment to unused variable actor_data
(F841)
apiserver/plane/api/views/issue_type.py
8-8: django.db.models.Case imported but unused
Remove unused import
(F401)
9-9: django.db.models.CharField imported but unused
Remove unused import
(F401)
10-10: django.db.models.Exists imported but unused
Remove unused import
(F401)
11-11: django.db.models.F imported but unused
Remove unused import
(F401)
12-12: django.db.models.Func imported but unused
Remove unused import
(F401)
13-13: django.db.models.Max imported but unused
Remove unused import
(F401)
14-14: django.db.models.OuterRef imported but unused
Remove unused import
(F401)
15-15: django.db.models.Q imported but unused
Remove unused import
(F401)
16-16: django.db.models.Value imported but unused
Remove unused import
(F401)
17-17: django.db.models.When imported but unused
Remove unused import
(F401)
18-18: django.db.models.Subquery imported but unused
Remove unused import
(F401)
25-25: rest_framework.parsers.MultiPartParser imported but unused
Remove unused import
(F401)
25-25: rest_framework.parsers.FormParser imported but unused
Remove unused import
(F401)
35-35: plane.bgtasks.issue_activities_task.issue_activity imported but unused
Remove unused import: plane.bgtasks.issue_activities_task.issue_activity
(F401)
140-140: Local variable requested_data is assigned to but never used
Remove assignment to unused variable requested_data
(F841)
141-141: Local variable current_instance is assigned to but never used
Remove assignment to unused variable current_instance
(F841)
142-142: Undefined name issue_comment
(F821)
162-162: Undefined name issue_comment
(F821)
200-200: Local variable workspace is assigned to but never used
Remove assignment to unused variable workspace
(F841)
236-236: Undefined name ValidationError
(F821)
apiserver/plane/app/views/view/base.py
3-3: django.db.models.Count imported but unused
Remove unused import: django.db.models.Count
(F401)
apiserver/plane/db/models/__init__.py
44-44: .issue.IssueCustomProperty imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
71-71: .project.ProjectPublicMember imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
115-115: .issue_type.IssueType imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
115-115: .issue_type.IssueTypeCustomProperty imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
apiserver/plane/api/views/__init__.py
2-2: .project.ProjectAPIEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
3-3: .project.ProjectArchiveUnarchiveAPIEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
16-16: .issue.IssueCustomPropertyUpdateAPIView imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
18-18: .issue_type.IssueTypeAPIEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
18-18: .issue_type.IssueTypeCustomPropertyAPIEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
19-19: .attachment.IssueAttachmentV2Endpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
37-37: .search.GlobalSearchEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
40-40: .webhook.WebhookEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
40-40: .webhook.WebhookLogsEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
41-41: .webhook.WebhookSecretRegenerateEndpoint imported but unused; consider removing, adding to __all__, or using a redundant alias
(F401)
apiserver/plane/api/views/project.py
253-253: Undefined name user
(F821)
apiserver/plane/app/views/issue/base.py
60-60: plane.utils.constants.ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAP imported but unused
Remove unused import: plane.utils.constants.ALLOWED_CUSTOM_PROPERTY_WORKSPACE_MAP
(F401)
72-72: plane.app.permissions.ProjectEntityPermission imported but unused
Remove unused import
(F401)
73-73: plane.app.permissions.ProjectLitePermission imported but unused
Remove unused import
(F401)
74-74: plane.app.permissions.ProjectMemberPermission imported but unused
Remove unused import
(F401)
apiserver/plane/utils/issue_filters.py
6-6: django.db.models.Q imported but unused
Remove unused import: django.db.models.Q
(F401)
apiserver/plane/api/views/attachment.py
9-9: plane.app.permissions.allow_permission imported but unused
Remove unused import: plane.app.permissions.allow_permission
(F401)
apiserver/plane/api/views/base.py
89-89: Multiple statements on one line (semicolon)
(E702)
apiserver/plane/api/views/issue.py
37-37: plane.api.serializers.IssueTypeSerializer imported but unused
Remove unused import: plane.api.serializers.IssueTypeSerializer
(F401)
57-57: plane.db.models.IssueType imported but unused
Remove unused import: plane.db.models.IssueType
(F401)
apiserver/plane/api/serializers/issue.py
38-38: Local variable uuid_obj is assigned to but never used
Remove assignment to unused variable uuid_obj
(F841)
apiserver/plane/api/urls/issue.py
10-10: plane.api.views.IssueTypeAPIEndpoint imported but unused
Remove unused import: plane.api.views.IssueTypeAPIEndpoint
(F401)
apiserver/plane/authentication/views/app/magic.py
287-287: Local variable is_app is assigned to but never used
Remove assignment to unused variable is_app
(F841)
🪛 Biome (1.9.4)
web/core/components/issues/issue-detail/issue-activity/activity/activity-list.tsx
[error] 47-47: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx
[error] 249-249: Missing key property for this element in iterable.
The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.
(lint/correctness/useJsxKeyInIterable)
web/core/components/issues/issue-detail/issue-activity/activity/actions/custom-properties.tsx
[error] 36-42: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
web/core/components/issues/issue-layouts/filters/header/filters/custom-properties.tsx
[error] 121-121: Unnecessary use of boolean literals in conditional expression.
Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with
(lint/complexity/noUselessTernary)
🔇 Additional comments (134)
web/app/provider.tsx (1)
43-51: Good implementation of the sign-out handler.The async function with proper error handling using toast notifications provides a good user experience.
apiserver/templates/emails/exports/analytics.html (1)
1-7: LGTM: Improved HTML formatting and standards compliance.The changes to this HTML email template improve readability through multi-line formatting and update the
<br/>tags to the XHTML-compliant<br />format. These changes enhance maintainability without altering the email's content or functionality.web/Dockerfile.web (1)
105-107: Container configuration properly implementedThe addition of the
EXPOSE 3000directive correctly documents the container's network port, while theCMD node web/server.js webinstruction defines the proper startup command. These are standard Docker practices that complete the container configuration.apiserver/plane/api/urls/project.py (1)
15-16: Ensure proper ID validation in view implementationChanging from
uuid:pktostr:pkremoves automatic UUID format validation at the URL dispatcher level. While this provides more flexibility, ensure that proper validation of project IDs is implemented in theProjectAPIEndpointview to prevent invalid IDs from causing issues.apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py (1)
19-23: Appropriate field modification for flexibilityMaking the
valuefield nullable and allowing blank values provides more flexibility for custom properties, which is a good change.web/core/components/workspace/sidebar/dropdown.tsx (1)
108-108:Details
❓ Verification inconclusive
Verify disabled dropdown button intention
Adding
disabled={true}makes the dropdown button non-interactive. This is a significant UX change that prevents users from accessing workspace selection functionality.Is this change intentional? If it's meant to be a temporary fix for a TypeScript error (as suggested by the PR title), consider addressing the underlying type issue instead of disabling the entire component functionality.
🏁 Script executed:
#!/bin/bash # Check if there are any TypeScript errors related to this component rg -B 3 -A 3 "SidebarDropdown" --glob "*.log" --glob "*.error" # Look for related property type errors in TypeScript config or error logs rg "property" --glob "*.log" --glob "*.error" | grep -i "type\|typescript\|ts"Length of output: 439
Action Required: Confirm Intention for the Disabled Dropdown Button
The dropdown button is permanently disabled with
disabled={true}, which removes access to the workspace selection functionality. Our initial automated search for related TypeScript errors did not return any results—though this may be due to filtering issues with the log search. Please verify whether this change is an intentional design decision or a temporary workaround for a TypeScript issue. If it is temporary, consider addressing the underlying type problem rather than disabling the component entirely.apiserver/plane/api/urls/state.py (1)
7-7:Details
❓ Verification inconclusive
Ensure consistent project_id handling across codebase
Changing
<uuid:project_id>to<str:project_id>in URL patterns makes the API more flexible in accepting project identifiers, but requires verification that all related code handles string IDs properly.This change may require updates to database queries and validation logic. Make sure the
StateAPIEndpointview and related code can handle string project IDs correctly:I'm particularly concerned about potential inconsistencies if other related endpoints still expect UUID project IDs.
Also applies to: 12-12
🏁 Script executed:
#!/bin/bash # Check for uses of project_id in the StateAPIEndpoint class rg -A 3 "project_id" "apiserver/plane/api/views/state.py" # Check for other URL patterns that might need similar updates for consistency rg "<uuid:project_id>" --glob="*.py" --glob="!*/migrations/*"Length of output: 17449
Action Required: Verify Consistency in Project ID Handling Across Endpoints
The URL change in
apiserver/plane/api/urls/state.py—switching from<uuid:project_id>to<str:project_id>—appears to work fine in theStateAPIEndpointas the view simply retrieves the project ID fromkwargsand uses it directly in queries and serializer contexts. However, our repository-wide search shows that several other endpoints (e.g., in files likeapiserver/plane/api/urls/inbox.pyandapiserver/plane/app/urls/state.py) still use<uuid:project_id>. This discrepancy raises two points for review:
Validation & Conversion: Confirm that the database model and related business logic can correctly work with a string value for
project_id. If the underlying field is a UUID, ensure that either:
- The string is converted/validated appropriately, or
- The design intentionally permits non-UUID values.
Endpoint Consistency: If a uniform handling of
project_idis desired across the API, decide whether to update the other URL patterns to<str:project_id>or to add conversion logic in theStateAPIEndpoint(and possibly in other views) to maintain consistency.Please revisit these areas to verify that the change does not introduce subtle bugs or inconsistency issues with other endpoints.
aio/nginx.conf (1)
6-8:Details
❓ Verification inconclusive
Consider reconciling duplicate
client_max_body_sizesettings.You have explicitly set
client_max_body_size 50M;on line 8 while also referencing${FILE_SIZE_LIMIT}on line 15. Verify whether you intend to override the environment variable value or if this duplication is unintentional, as it can lead to confusion or inconsistent behavior.
🏁 Script executed:
#!/bin/bash # Description: Check for references to client_max_body_size and FILE_SIZE_LIMIT in aio/nginx.conf to confirm if you're intentionally overriding the environment variable. rg 'client_max_body_size|FILE_SIZE_LIMIT' aio/nginx.conf -A 2Length of output: 223
Action: Reconcile Duplicate
client_max_body_sizeSettingsIt appears that the configuration file sets
client_max_body_sizetwice in different contexts:
- A fixed value of
50Mis set (around line 8).- Later, within the server block, an environment variable is used:
${FILE_SIZE_LIMIT}.This duplication may be unintentional or could lead to unpredictable behavior. Please verify if the fixed value is meant to override the variable or if both declarations should be consolidated for consistency.
nginx/nginx.conf.template (1)
6-8:Details
❓ Verification inconclusive
Double-check configuration consistency.
These added directives align with the changes in
aio/nginx.conf. However, as withaio/nginx.conf, confirm whether you intend to override the environment variable-basedclient_max_body_size(line 15) with a hard-coded 50M limit.
🏁 Script executed:
#!/bin/bash # Description: Verify references to client_max_body_size and FILE_SIZE_LIMIT in nginx.conf.template for consistency. rg 'client_max_body_size|FILE_SIZE_LIMIT' nginx/nginx.conf.template -A 2Length of output: 234
Nginx Configuration Consistency Check
- In
nginx/nginx.conf.template, there is a global directive settingclient_max_body_size 50M;while within theserver { … }block it usesclient_max_body_size ${FILE_SIZE_LIMIT};.- Please confirm if the intention is to override the environment variable-based setting with the hard-coded 50M value, as done in
aio/nginx.conf, or if the two settings should be unified.web/core/constants/dashboard.ts (1)
261-268: The Projects menu item is commented out.This change removes the "Projects" option from the sidebar menu. Make sure this is intentional and won't affect user navigation within the application.
Is this temporary or part of a redesign to simplify the sidebar? Consider adding a comment explaining why these menu items are commented out rather than completely removed if this is a temporary change.
apiserver/plane/app/serializers/issue.py (4)
667-678: New serializer added for custom properties.Added
IssueCustomPropertySerializerto handle custom properties for issues.This serializer properly defines the fields and read-only properties for the
IssueCustomPropertymodel, which will help in handling custom property data in API responses.
740-741: Added type_id field to IssueSerializer.Added
type_idto the fields of theIssueSerializer.This field is necessary for properly identifying issue types, which appears to be related to the custom properties functionality being implemented.
759-760: Added custom_properties field to IssueDetailSerializer.Incorporated the custom properties serializer into the
IssueDetailSerializerand added it to the fields list.This change properly integrates custom properties with issue details, allowing them to be included in API responses when fetching issue details.
Also applies to: 765-766
711-721:Details
❓ Verification inconclusive
Added multiple reference fields to issue serializer.
Added fields like
trip_reference_number,hub_code,customer_name, etc. to theIssueSerializer.These appear to be domain-specific reference fields. Ensure that these fields are properly defined in the Issue model. Additionally, consider grouping these reference fields into a nested structure if they logically belong together.
🏁 Script executed:
#!/bin/bash # Verify that these fields exist in the Issue model grep -A 30 "class Issue" apiserver/plane/db/models/issue.py | grep -E "trip_reference_number|reference_number|hub_code|hub_name|customer_code|customer_name|vendor_name|vendor_code|worker_code|worker_name"Length of output: 206
Action: Verify model field definitions and consider grouping related reference fields
The added reference fields (
trip_reference_number,reference_number,hub_code,hub_name,customer_code,customer_name,vendor_name,vendor_code,worker_code,worker_name) need to be confirmed as being defined in the Issue model (apiserver/plane/db/models/issue.py). The initial grep command did not produce any output, so please manually verify (or re-run an extensive search) to ensure these fields are present. Additionally, if these reference-related fields represent a cohesive domain group, consider refactoring them into a nested structure for better organization.web/core/components/issues/index.ts (1)
15-15: Added export for custom properties module.Added a new export statement for the custom properties components.
This change correctly exports the custom properties components, making them available to be imported by other parts of the application. This is consistent with the overall approach of exporting all components through index files.
web/core/components/issues/issue-layouts/filters/header/filters/index.ts (1)
14-14: Clean addition of new export for additional properties filteringThis export follows the established pattern in the file and makes the components from the additional-properties module available to importers of this index file, enhancing the filtering capabilities with custom properties.
web/core/components/issues/issue-layouts/spreadsheet/columns/index.ts (1)
15-15: Export addition looks goodThis new export follows the consistent pattern in the file and makes the standard-property-column components available through this index. This change supports the handling of custom properties in the issue management system.
web/core/components/issues/issue-layouts/filters/applied-filters/index.ts (1)
12-12: Export properly implemented for applied filtersThis addition correctly follows the established pattern and makes the AppliedAdditionalPropertiesFilters component available to importers. This enhances the filtering capabilities in the UI for custom properties.
web/core/components/issues/issue-detail/issue-activity/activity/actions/index.ts (1)
20-20: LGTM! Export for custom properties activity actionsThis export correctly exposes the custom properties module in the activity actions index. This enables proper tracking and display of custom property changes in the issue activity feed.
apiserver/plane/app/permissions/__init__.py (1)
14-14:Details
✅ Verification successful
New permission import needs to be verified
The
ProjectEntityGuestPermissionhas been added to the imports. This permission class extends access control to accommodate guest users for project-related functionalities, but the static analysis indicates it might be unused within this context.
🏁 Script executed:
#!/bin/bash # Check if ProjectEntityGuestPermission is used in the codebase echo "Searching for references to ProjectEntityGuestPermission:" rg "ProjectEntityGuestPermission" --type py -A 2 -B 2Length of output: 1537
Verified usage of ProjectEntityGuestPermission in issue views
The new permission import is confirmed to be used in the codebase—in particular, it's referenced in the Issue view within
apiserver/plane/api/views/issue.py(both where it is explicitly mentioned and in thepermission_classesattribute). This verifies that the import isn't unused, and no further changes are required.🧰 Tools
🪛 Ruff (0.8.2)
14-14:
.project.ProjectEntityGuestPermissionimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
apiserver/plane/app/views/__init__.py (1)
135-136:Details
✅ Verification successful
Verify usage of newly imported search endpoints
The
SearchAPIEndpointandSearchSingleValueAPIclasses have been imported from.issue.base, but static analysis indicates they might be unused. These endpoints provide search capabilities for issue-related fields within a workspace and project.
🏁 Script executed:
#!/bin/bash # Check if the newly imported search endpoints are used in the codebase echo "Searching for references to SearchAPIEndpoint:" rg "SearchAPIEndpoint" --type py -A 2 -B 2 echo "Searching for references to SearchSingleValueAPI:" rg "SearchSingleValueAPI" --type py -A 2 -B 2 # Check for URL patterns that might utilize these endpoints echo "Checking URL patterns that might use these endpoints:" rg "path\(.*search.*" --type py -A 2 -B 2Length of output: 2974
Search endpoints usage verified—imports are in use
After verifying the codebase:
- SearchAPIEndpoint is defined in
apiserver/plane/app/views/issue/base.pyand referenced inapiserver/plane/app/urls/issue.py(e.g., mapped to the URL pattern for"workspaces/<str:slug>/projects/<str:project_id>/search").- SearchSingleValueAPI is defined in
apiserver/plane/app/views/issue/base.pyand similarly used in URL configurations withinapiserver/plane/app/urls/issue.py.These findings confirm that the imported endpoints in
apiserver/plane/app/views/__init__.pyare actively used within the project. No changes are required.🧰 Tools
🪛 Ruff (0.8.2)
135-135:
.issue.base.SearchAPIEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
136-136:
.issue.base.SearchSingleValueAPIimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py (1)
1-18: Migration corrects spelling in field nameThis migration fixes a typo in the field name, changing
issue_type_custom_proertyto the correctly spelledissue_type_custom_property. This is part of a sequence of migrations that have been refining the schema of theissuecustompropertymodel.web/core/constants/analytics.ts (1)
57-57: Fixed syntax by removing trailing commaThe trailing comma has been removed from the last object in the
ANALYTICS_X_AXIS_VALUESarray. While trailing commas are valid in modern JavaScript/TypeScript and can make diffs cleaner when adding new items, this change likely aligns with the project's style guidelines.admin/Dockerfile.admin (1)
86-88: Good Docker configurationThe exposed port and CMD instruction correctly define how the container should be run, following Docker best practices.
web/core/components/issues/issue-layouts/spreadsheet/issue-column.tsx (1)
46-46:Details
❓ Verification inconclusive
Fix for property type propagation
This change correctly passes the property prop to the Column component, which is properly typed as keyof IIssueDisplayProperties. This addresses a TypeScript error where a required prop wasn't being passed down to the child component.
🏁 Script executed:
#!/bin/bash # Check the Column component to confirm it expects a property prop echo "Checking SPREADSHEET_PROPERTY_DETAILS to understand Column component requirements..." rg -A 5 "SPREADSHEET_PROPERTY_DETAILS" --type tsxLength of output: 256
Action Required: Re-run Verification Script for TSX Files
The initial script failed because ripgrep didn’t recognize the "tsx" file type. Please run the updated script below—which uses a glob pattern to properly target TSX files—to verify that the Column component (or related component) references
SPREADSHEET_PROPERTY_DETAILSand that thepropertyprop is correctly typed askeyof IIssueDisplayProperties.#!/bin/bash # Re-checking SPREADSHEET_PROPERTY_DETAILS in TSX files using glob pattern echo "Re-checking SPREADSHEET_PROPERTY_DETAILS in TSX files with -g pattern..." rg -A 5 "SPREADSHEET_PROPERTY_DETAILS" -g "*.tsx"Once you verify that the expected output appears and confirms that the Column component requires and correctly types the
propertyprop, you can confirm that the change (passingproperty={property}) resolves the TypeScript error.web/ce/constants/project/settings/features.tsx (1)
87-88: Time tracking feature now available for all usersThe changes make time tracking accessible to all users by setting
isPro: falseandisEnabled: true. This modification democratizes the feature, removing its premium-only restriction.web/app/[workspaceSlug]/(projects)/header.tsx (2)
3-8: GitHub link and related imports removed from headerThe commented imports suggest a deliberate removal of GitHub integration from the header component.
14-14: Event tracking constant no longer neededThe
GITHUB_REDIRECTEDconstant has been commented out since the GitHub link in the header has been removed.admin/ce/components/common/upgrade-button.tsx (1)
12-16: Upgrade button functionality disabledThe upgrade button has been effectively disabled by replacing it with an empty anchor element. The original implementation directing users to "plane.so/one" is preserved in comments for potential future restoration.
apiserver/plane/utils/grouper.py (1)
97-106: Custom fields added for issue resultsThese additions to the
required_fieldslist enhance the issue data response with transport/logistics-specific fields like trip references, hub details, customer and vendor information. This change ensures these custom properties are properly included in query results.apiserver/requirements/base.txt (3)
13-13: New dependency for environment variable managementAdding
python-dotenvsuggests the codebase now uses environment variables from .env files for configuration, which is a good practice for managing different deployment environments.
33-33: Minor version upgrade for django-storagesUpgrading django-storages from 1.14.2 to 1.14.4 is likely for bug fixes or improvements.
4-4:Details
❓ Verification inconclusive
Verify Django downgrade is intentional
Django has been downgraded from 4.2.16 to 4.2.14. While this might be for compatibility reasons, downgrading could have security implications if the newer version contained security fixes.
🌐 Web query:
Are there any security fixes in Django 4.2.16 that are not in Django 4.2.14?💡 Result:
Django 4.2.16 includes two security fixes not present in 4.2.14:
Security Fixes Introduced in 4.2.16
CVE-2024-45230:
Moderate-severity denial-of-service vulnerability indjango.utils.html.urlize(), where processing specific character sequences in large inputs could exhaust system resources[1][4][10].CVE-2024-45231:
Low-severity user email enumeration vulnerability via password reset failures. Attackers could infer valid user emails by observing error responses when email delivery failed[1][4][16].Security Fixes in 4.2.14 (Not Present in 4.2.16)
Django 4.2.14 addressed four vulnerabilities resolved in earlier releases:
- Denial-of-service in
urlize()via excessive brackets (CVE-2024-38875)- Username enumeration via timing attacks (CVE-2024-39329)
- Directory traversal via custom
Storageimplementations (CVE-2024-39330)- DoS in language code validation (CVE-2024-39614)[6].
The 4.2.16 release only addresses the two newer CVEs listed above. For comprehensive protection, upgrading directly to 4.2.16 (or later) is required to include all cumulative security patches[1][6].
Citations:
- 1: https://docs.djangoproject.com/en/5.1/releases/4.2.16/
- 2: https://upgradedjango.com/4.2/
- 3: https://community.theforeman.org/t/critical-vulnerabilities-in-django-affect-foreman-katello/39129
- 4: https://www.djangoproject.com/weblog/2024/sep/03/security-releases/
- 5: https://django.readthedocs.io/en/latest/releases/4.2.15.html
- 6: https://docs.djangoproject.com/en/5.1/releases/4.2.14/
- 7: https://security.snyk.io/package/pip/django/4.2.16
- 8: https://docs.djangoproject.com/en/5.1/releases/4.2/
- 9: https://docs.djangoproject.com/en/5.1/releases/security/
- 10: https://www.tenable.com/plugins/nessus/206676
- 11: https://docs.djangoproject.com/en/5.1/releases/
- 12: https://security.snyk.io/package/pip/django/2.2.2
- 13: https://forum.djangoproject.com/t/python-3-13-0-with-django-4-2-16/35500
- 14: https://www.tenable.com/plugins/nessus/206676/changelog
- 15: https://security.snyk.io/package/pip/django/2.0.2
- 16: https://groups.google.com/g/django-developers/c/2TVE2MbSbe0
- 17: https://www.tenable.com/plugins/nessus/206676/changelog/1.9
- 18: https://security.snyk.io/package/pip/django/4.2
- 19: https://git.boiledscript.com/mirror/guix/commit/249db21652133744ba1b8a079d0709d838f2248e
Security Implications: Confirm Intentional Django Version Downgrade
File:
apiserver/requirements/base.txt(Line 4)The current change downgrades Django from 4.2.16 to 4.2.14. Note that Django 4.2.16 introduced two important security fixes that are missing in 4.2.14:
- CVE-2024-45230: A moderate-severity denial-of-service vulnerability in
django.utils.html.urlize().- CVE-2024-45231: A low-severity issue regarding user email enumeration via password reset failures.
Please verify that this downgrade is intentional and that any compatibility reasons have been weighed against the potential security implications. If the downgrade remains necessary, consider documenting the rationale and any planned mitigations.
apiserver/plane/api/serializers/__init__.py (1)
13-13: New serializers for custom properties and issue typesThe addition of
IssueCustomPropertySerializer,IssueTypeSerializer, andIssueTypeCustomPropertySerializerto the package exports enhances the API's capability to handle custom properties and issue types.While static analysis flags these as unused imports, this is a common pattern in Python where
__init__.pyfiles intentionally re-export symbols to simplify imports for consumers of the package.Also applies to: 15-15
🧰 Tools
🪛 Ruff (0.8.2)
13-13:
.issue.IssueCustomPropertySerializerimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py (1)
14-18: Improved relationship between issue custom properties and typesThis migration properly modifies the
issue_typefield in theissuecustompropertymodel to be an optional foreign key toissuetypecustomproperty. Theon_delete=SET_NULLbehavior ensures that deleting an issue type custom property won't cascade delete the issue custom property itself, which prevents data loss.The defined related name
issue_type_custom_propertyprovides a clear reverse lookup path from issue type custom properties to their associated issue custom properties.apiserver/plane/app/views/base.py (1)
123-124: Good debugging enhancement!Adding detailed query logging when there are more than 20 queries will help identify potential N+1 query issues during development.
apiserver/supervisord.conf (1)
1-16: Well-structured Supervisor configuration for CeleryThe configuration properly sets up:
- Celery worker with appropriate log level
- Flower monitoring tool on port 5555
- Proper log file paths for both services
- Auto-restart for reliability
This is a good approach for managing background task processing in the application.
web/core/components/issues/issue-layouts/filters/applied-filters/filters-list.tsx (3)
17-17: Good addition of the AppliedAdditionalPropertiesFilters component.This import correctly includes the new component for handling additional property filters.
40-40: Well-defined constant for additional filter properties.The
additionalFiltersconstant properly defines the list of filter keys that will be handled by the additional properties filter component.
139-145: Properly implemented conditional rendering for additional properties filters.The implementation follows the established pattern in the codebase and correctly passes the necessary props to the
AppliedAdditionalPropertiesFilterscomponent. This enhances the filtering functionality with additional property support.apiserver/plane/app/urls/issue.py (1)
27-28: Good addition of search endpoints.These imports correctly include the necessary view classes for the new search functionality.
apiserver/plane/authentication/adapter/base.py (2)
152-155: Fixed username handling for user creationThe code now properly checks for a username from user data before defaulting to a UUID. This enhances the authentication flow by allowing pre-defined usernames to be preserved when available.
175-175: Minor formatting improvementAdded a blank line after retrieving user details for better code readability.
web/core/components/issues/issue-layouts/filters/applied-filters/additional-properties.tsx (1)
1-33: LGTM: Well-implemented filter component for custom propertiesThis new component correctly handles the display and removal of additional property filters. The implementation follows React best practices with proper typing and observer pattern for reactivity.
web/core/components/issues/issue-detail/issue-activity/activity/activity-list.tsx (1)
27-27: Added import for custom property activity handlingProperly imported the
IssueCustomPropertyActivitycomponent to handle custom property changes in the activity list.web/app/workspace-invitations/page.tsx (1)
7-7: Removed Star icon from importsThe Star icon import has been removed from lucide-react imports, aligning with the removal of the GitHub star call-to-action from the UI.
nginx/nginx.conf.dev (1)
6-8: Approved configuration for handling larger requests.These nginx configuration directives improve handling of large request bodies and enable chunked transfer encoding.
apiserver/plane/api/serializers/issue_type.py (1)
7-24: LGTM - The IssueTypeSerializer implementation looks goodThe implementation properly extends the BaseSerializer and adds the workspace_id from context during validation. The Meta class correctly defines read-only fields and exclusions.
apiserver/plane/settings/storage.py (3)
16-17: LGTM - Added standard storage class variablesThe added class variables
file_overwriteandlocationfollow Django's storage backend conventions.
22-26: LGTM - Good implementation of get_available_name methodThe implementation follows Django's storage pattern, returning the original name when file_overwrite is True, and using the parent class implementation otherwise.
49-49:Details
❓ Verification inconclusive
Verify HTTPS enforcement behavior
The URL is now hardcoded to use HTTPS protocol. Make sure this change doesn't break functionality for environments where HTTP might be required.
🏁 Script executed:
#!/bin/bash # Check if there are any environment-specific configurations that might rely on HTTP grep -r "AWS_S3_ENDPOINT_URL.*http:" --include="*.py" --include="*.env*" . grep -r "MINIO_ENDPOINT_URL.*http:" --include="*.py" --include="*.env*" .Length of output: 360
Action Required: Confirm HTTPS Enforcement Impact on Env Configurations
The code now hardcodes the URL scheme to HTTPS with:
f"https://{request.get_host()}"However, our grep output from configuration files shows that some environment examples still set endpoints (e.g.,
AWS_S3_ENDPOINT_URLin.env.exampleandvariables.env) to use HTTP (http://plane-minio:9000). Please verify that using HTTPS in the code doesn’t conflict with these environments. If non-HTTPS endpoints are needed (for example, in development or local testing setups), consider making the URL scheme configurable or updating the environment documentation accordingly.docker-compose-local.yml (3)
23-24: Port exposure for MinIO improves local development.Exposing the MinIO console port (9090) on the host makes it easier to access the web console for managing the object storage during local development. This is a good improvement.
38-39: Port exposure for PostgreSQL enables direct database access.Exposing the PostgreSQL port (5432) allows direct connections to the database from the host machine, which is helpful for debugging and using database management tools during local development.
115-116: Interactive terminal access for the API service is useful for debugging.Adding
stdin_open: trueandtty: trueto the API service enables interactive terminal sessions, which makes it easier to debug the API service using tools likedocker attachor when running withdocker-compose up.apiserver/plane/api/middleware/api_authentication.py (1)
67-67: Fix method call to match the corrected method name.Update the call to
validate_api_tokento ensure it passes theassume_role_valueparameter correctly.apiserver/plane/settings/common.py (4)
28-28: Good addition for environment variable loading.Adding the dotenv library for environment variable loading improves configuration flexibility across different environments.
156-156: Approved CORS header addition.Adding the "X-Assume-Role" header to CORS_ALLOW_HEADERS is necessary for cross-origin requests that use this header.
275-275: Verify the impact of enabling file overwriting in S3.Changing AWS_S3_FILE_OVERWRITE to True means files in S3 can be overwritten, which could lead to data loss if not managed properly. Ensure this is the intended behavior and that there are mechanisms to handle potential conflicts.
365-368:Details
❓ Verification inconclusive
Security concerns with cookie settings.
The security-related cookie settings have been commented out and modified. SESSION_COOKIE_SECURE should be enabled in production environments to prevent cookies from being sent over unencrypted connections.
🏁 Script executed:
#!/bin/bash # Check if this is a production configuration file grep -A 5 -B 5 "PRODUCTION" apiserver/plane/settings/common.py # Check if there are different settings in production-specific settings files find apiserver/plane/settings -name "*.py" -exec grep -l "SESSION_COOKIE_SECURE" {} \;Length of output: 187
Action Required: Validate Production Cookie Security Settings
The production configuration (in
apiserver/plane/settings/common.py) now setsSESSION_COOKIE_SECUREvia the variablesecure_originsinstead of a hard-codedTrue. Since this is the only place this setting appears, please verify that in your production environmentsecure_originsevaluates toTrue, ensuring cookies are only sent over encrypted connections. Ifsecure_originsis intended to support multiple environments dynamically, please add documentation or inline comments clarifying its expected value in production.apiserver/plane/api/urls/webhook.py (1)
9-31: URL patterns follow RESTful conventions.The URL patterns are well-structured and follow RESTful conventions, clearly identifying resources and actions.
apiserver/plane/api/views/__init__.py (3)
1-4: Improved code formatting for imports.The multi-line import format improves readability.
🧰 Tools
🪛 Ruff (0.8.2)
2-2:
.project.ProjectAPIEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
3-3:
.project.ProjectArchiveUnarchiveAPIEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
16-17: Approved import for custom property update view.The import for
IssueCustomPropertyUpdateAPIViewis correctly placed within the issue-related imports.🧰 Tools
🪛 Ruff (0.8.2)
16-16:
.issue.IssueCustomPropertyUpdateAPIViewimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
18-19: Added imports for issue type and attachment endpoints.The imports for
IssueTypeAPIEndpoint,IssueTypeCustomPropertyAPIEndpoint, andIssueAttachmentV2Endpointare necessary for the expanded functionality.🧰 Tools
🪛 Ruff (0.8.2)
18-18:
.issue_type.IssueTypeAPIEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
18-18:
.issue_type.IssueTypeCustomPropertyAPIEndpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
19-19:
.attachment.IssueAttachmentV2Endpointimported but unused; consider removing, adding to__all__, or using a redundant alias(F401)
web/core/components/issues/issue-detail/issue-activity/activity/actions/custom-properties.tsx (1)
1-13: Properly structured React component with TypeScript.The component imports, type definitions, and setup follow best practices for React with TypeScript.
apiserver/plane/app/permissions/project.py (8)
18-19: Confirm superuser bypass is intentional.These lines grant unrestricted access to superusers. If that’s expected, it’s fine. Otherwise, verify that this is the intended behavior in all scenarios.
33-33: Recheck role inclusion for project creation.The comment above suggests only workspace owners or admins should create projects, but this line explicitly includes the
Guestrole. Ensure that this is desired or correct any mismatched logic or docstring.
56-56: No functional change.A blank line was added here. This is purely cosmetic; no further action needed.
68-68: Verify role set for creating projects.Including the
Guestrole here is the same scenario as on line 33. Confirm whether guests should truly be able to perform project creation or modifications.
73-73: No functional change.Another blank line added. No action needed.
77-77: Check role-based logic for project updates.The code comment states “Only Project Admins,” but the
role__inlist includesGuestandMember. Confirm that it’s correct to let guests update project attributes.
88-89: Superuser override.Same pattern as before. Ensure there’s no risk in automatically granting all superusers total access without additional checks.
113-117: Role expansion includes Guest.These lines allow guests to create and edit project attributes. If that matches your requirements, great. If not, revert or adjust the role set accordingly.
apiserver/plane/api/views/base.py (3)
11-11: Validate new imports.
ProjectandUserare imported. Verify they are actually used within this module to avoid introducing unused dependencies.
115-117: Check side effects of modifyingkwargsandrequest.user.These calls can have significant side effects (e.g., creating workspace memberships). Confirm concurrency logic, user validation, and error handling in upstream and downstream code so they can handle unexpected modifies to
kwargsandrequest.user.
165-176: Confirm membership logic inensure_member_in_workspace.This relies on
MagicSignInEndpointagain, which might cause side effects (like auto-creating workspace members). Validate that this is desired for all inbound requests. If not, consider restricting it to specific endpoints.apiserver/plane/app/views/view/base.py (2)
63-74: LGTM! Good serializer implementation.The serializer is well-structured with appropriate field definitions and read-only fields.
331-339: Good approach to handling custom properties filtering.Creating a copy of the filters before modifying them is a good practice. The implementation correctly separates custom properties from other filters.
web/core/services/workspace.service.ts (1)
281-290: LGTM! API method follows established patterns.The implementation of
getIssuesCustomPropertiesfollows the standard pattern used throughout the service.apiserver/plane/authentication/provider/credentials/magic_code.py (1)
150-150:Details
❓ Verification inconclusive
Verify impact of changing is_password_autoset to False.
Changing
is_password_autosetfromTruetoFalsemay affect how password resets work. Ensure this change aligns with the intended authentication flow.
🏁 Script executed:
#!/bin/bash # Search for places where is_password_autoset is used in the codebase rg "is_password_autoset" --type pyLength of output: 2812
Verify is_password_autoset behavior across authentication flows
After reviewing the codebase, we found that in credential-based providers (e.g., in both
magic_code.pyandemail.py), the flag is explicitly set toFalse—which aligns with the user model default—while OAuth providers (e.g., ingitlab.py,google.py,github.py) deliberately set it toTrue. This inconsistency suggests that the different authentication flows are expected to handle password setup differently.
- Action Points:
- Confirm that for credential-based authentication (magic code/email), setting
is_password_autosettoFalseis intentional and does not inadvertently impact password reset logic.- Double-check that the divergence from OAuth providers’ behavior (where the flag remains
True) is well-documented and aligns with your overall authentication flow.packages/types/src/view-props.d.ts (2)
83-89: Type expansion for custom properties improves filter capabilitiesThe addition of custom property types for logistics data (customer codes, hub codes, reference numbers, etc.) provides more granular filtering capabilities for issues, aligning with the requirements in the PR objective to fix TypeScript errors related to property types.
109-115: Consistent type definitions for filter optionsThe filter options interface has been properly updated to include all the new custom properties, maintaining type consistency with the
TIssueParamstype above. This ensures type safety when using these properties in filters.apiserver/plane/api/urls/issue.py (2)
71-79: Updated to use new IssueAttachmentV2EndpointThe attachment endpoint has been updated to use the V2 version of the API, which according to the related code snippets handles file uploads more effectively with presigned URLs and better error handling.
21-27:Details
✅ Verification successful
Project ID parameter type changed from UUID to string
The parameter type for
project_idhas been changed fromuuidtostrin all URL patterns. Ensure all related views and functions that consume this parameter have been updated to handle string values rather than UUIDs.
🏁 Script executed:
#!/bin/bash # Check if project_id is still treated as UUID in related views rg -A 5 "def.*project_id.*" --glob="apiserver/plane/api/views/issue.py"Length of output: 10049
Action Required: Confirm Handling of
project_idas StringThe shell script verification confirms that all instance methods in
apiserver/plane/api/views/issue.pynow accept theproject_idparameter as a string. For example, calls such as:
project = Project.objects.get(pk=project_id)directly use the incoming
project_idvalue without any conversion to a UUID. Please verify that downstream logic (e.g., model field types and any implicit validations) properly supports string values as expected.apiserver/plane/api/views/project.py (1)
34-122: Good refactoring of project creation logicExtracting the project creation logic into a separate function improves code organization and maintainability. The function handles all the necessary steps for project creation in a cohesive way.
web/core/constants/issue.ts (2)
380-386: Added custom properties to issue list filtersThe addition of custom properties to the filters array provides more flexible and powerful filtering capabilities, particularly for logistics-related data like hub codes and reference numbers.
326-332: Added custom properties to my_issues spreadsheet filtersAdding these custom property filters to the My Issues view enables consistent filtering capabilities across different views.
apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py (1)
1-69: Migration file looks well structured.This migration creates two new models:
ProjectCustomPropertyandIssueCustomPropertywith appropriate fields, relationships, and constraints. The unique constraints onProjectCustomPropertyensure data integrity by preventing duplicate entries.packages/types/src/issues/issue.d.ts (1)
61-67: New properties align with PR objectives.These new properties properly extend the
TIssuetype with custom properties and shipping-related fields, which addresses the TypeScript error mentioned in the PR objectives.web/core/store/issue/helpers/issue-filter-helper.store.ts (3)
85-85: Filter implementation for custom properties.The custom properties filter has been added correctly to match the pattern of the other filters.
107-112: Consistent implementation of shipping-related filters.These additional filters for shipping-related fields are implemented correctly and follow the established pattern.
154-159: Consistent implementation in computedFilters method.The shipping-related properties are correctly handled in the computedFilters method, defaulting to null when not present.
web/core/components/issues/issue-detail/sidebar.tsx (3)
60-60: Default initialization of customProperties is good.Using
issue?.custom_properties || []ensures that we always have an array to work with, even if the custom properties are undefined.
345-357: Good implementation for displaying additional properties.The map function correctly displays the additional properties when they exist on the issue. The null check ensures that undefined properties aren't rendered.
359-365: Ensure CustomProperties component gracefully handles different property formats.While the component receives the customProperties with an Array check, it's not clear from the code shown whether the CustomProperties component itself properly handles all edge cases (like invalid property structures).
Please check the implementation of the CustomProperties component to ensure it handles edge cases appropriately, particularly:
- When customProperties is an empty array
- When an individual property doesn't match the expected structure
- When the issue_type_id is null or invalid
apiserver/plane/api/views/member.py (6)
22-22: Good addition of the Profile model import.The import of the Profile model is appropriate for the new profile-related functionality being added in this file.
66-71: Simplified validation logic.The validation logic has been simplified to only check for email presence, removing the display_name requirement. The error message has been updated to reflect this change.
94-94: Good practice: Converting email to lowercase when querying.Converting the email to lowercase before querying the database is a good practice to ensure case-insensitive email lookups.
117-123: Well-structured user data dictionary.The user data is now organized in a clear dictionary structure before being used for user creation, improving code readability and maintainability.
138-138: Good refactoring: Using helper method for workspace member creation.Refactoring the workspace member creation into a separate helper method improves code organization and reusability.
142-142: Good refactoring: Using helper method for project member creation.Refactoring the project member creation into a separate helper method improves code organization and reusability.
apiserver/Dockerfile.api (4)
33-36: Good addition of Flower for Celery monitoring.Adding Flower for Celery monitoring is a good enhancement, but be aware that setting
FLOWER_UNAUTHENTICATED_API=truecould pose security risks in production environments.Consider implementing authentication for Flower in production environments to prevent unauthorized access to monitoring data.
51-52: Updated port exposure to include Flower UI port.Exposing both the API and Flower UI ports is necessary for the new functionality.
54-61: Good use of build arguments for environment file handling.Using build arguments to handle environment file paths is a flexible approach that allows for different configurations in different environments.
63-65:Details
❓ Verification inconclusive
Conditional database migration execution.
The conditional execution of database migrations based on
ENV_TYPEis a good approach to ensure migrations run only in the appropriate environment.
🏁 Script executed:
#!/bin/bash # Check if ENV_TYPE is declared anywhere in the Dockerfile or related configuration grep -r "ENV ENV_TYPE" --include="*.yml" --include="Dockerfile*" .Length of output: 68
Action Required: Verify External ENV_TYPE Definition
The conditional execution of database migrations based on
ENV_TYPEis a sound technique. However, our initial search did not reveal any explicit definition ofENV_TYPEin Dockerfiles or YAML configs, indicating that this variable is likely expected to be provided externally (for example, via runtime environment variables or CI/CD settings). Please ensure that:
ENV_TYPEis appropriately set in your deployment or runtime environment.- There is clear documentation on where and how
ENV_TYPEis defined to avoid any unintended behavior during container startup.If
ENV_TYPEis managed externally and this design is intentional, no changes are needed. Otherwise, consider providing a default definition or including it in your configuration files for clarity.web/core/components/issues/issue-layouts/filters/header/filters/additional-properties.tsx (1)
10-16: Well-defined Props interface.The Props interface is well-defined with appropriate types for each property.
web/core/constants/spreadsheet.ts (3)
14-14: Good import of the Tags icon.The Tags icon is appropriately imported for use in the new property definitions.
36-36: Good component import for property display.The SpreadsheetStandardPropertyColumn import is necessary to support the new property definitions.
288-297: Property list additions.The additions to SPREADSHEET_PROPERTY_LIST are necessary to include the new properties in the available options.
web/core/components/issues/peek-overview/properties.tsx (2)
61-62: Confirm default value forissue_type_id.Using a hard-coded fallback (
"afd30f86-5ae5-428c-aa3a-e633ea973740") might cause unexpected behavior or indicates a placeholder that needs verification.Would you like to confirm whether this is the correct default value or if it should be dynamically derived from the workspace or project settings?
359-365: Looks good overall.Rendering
CustomPropertieshere cleanly integrates with the rest of the component.web/core/components/issues/custom-properties.tsx (1)
158-188: Validate potential key collisions inmergedCustomProperties.map(...).You are using
element.keyas the React key. If your API or local data ever include duplicate keys, React will issue a warning and render updates incorrectly. Make sure the server enforces unique property keys per issue type or consider appending a unique identifier to avoid potential collisions.apiserver/plane/api/serializers/issue.py (1)
314-331: Confirm whether deleting then recreating all custom properties is intentional.In the update method, existing
IssueCustomPropertyentries are deleted and replaced with the new list. If partial updates are desired, consider a more selective approach that updates or inserts only the changed properties, preserving the others.apiserver/plane/db/models/issue.py (2)
79-88: Enhanced display properties look good.Adding these references (
trip_reference_number,reference_number,hub_code, etc.) expands the displayed attributes. The JSON field remains consistent and no immediate issues appear.
733-755: NewIssueCustomPropertymodel design appears solid.The structure is clear, with a straightforward relationship to
IssueandIssueTypeCustomProperty. The naming is consistent, and the default ordering meets typical use cases. No further issues identified.apiserver/plane/bgtasks/issue_activities_task.py (2)
394-394: Great flexibility with dynamicverbusage.Using the
verb=verbparameter instead of a hard-coded string provides better flexibility and reusability intrack_assignees.
1740-1741: Nice addition ofcustom_propertymappings.Adding
"custom_property.activity.updated"and"custom_property.activity.created"toACTIVITY_MAPPERensures consistency with other tracked changes.apiserver/plane/api/views/webhook.py (5)
1-14: Imports appear fine.The chosen imports are minimal and relevant for the functionalities required.
40-78: Efficient retrieval of single vs. multiple webhooks.Differentiating between a single webhook (by
pk) and multiple webhooks is straightforward. Verify that only authorized users can view workspace-wide webhooks.
104-108: Delete method is straightforward.Uses the correct HTTP 204 status code to indicate success and clearly handles resource removal.
110-119: Regenerating secret keys with admin permission.Using
@allow_permissionwithallowed_roles=[ROLE.ADMIN]ensures that only admins can regenerate the secret key, which is solid from a security standpoint.
121-130: Restrict logs to admin roles.Retrieving logs for a specific webhook is well-implemented, and the permission check helps ensure only authorized users can access logs.
apiserver/plane/api/views/search.py (6)
1-13: Imports look aligned with required modules.No issues detected with the chosen imports.
29-36: Clear docstring forGlobalSearchEndpoint.The docstring provides a concise overview of the endpoint’s responsibility and functionality.
50-66: Consistent approach for project filtering.The logic for including
archived_at__isnull=Trueand checking active memberships is aligned with the rest of the application.
107-131: Cycle filtering logic aligns with other sections.The approach to check for active members and non-archived projects is consistent and looks solid.
157-210: Subquery usage for project-page associations is commendable.The use of
OuterRefandSubqueryto fetch the project ID is elegant. If handling large data sets, confirm that necessary indexes are present for performance.
211-235: Cohesive approach for filteringIssueView.The inclusion of active members and non-archived projects is consistent. Watch out for potential performance bottlenecks if the dataset grows large.
demo.Jenkinsfile (3)
95-124: Parallel builds look good.The parallel Docker image builds are well-structured. The use of
dockerBuildArgsin the API service build is clear and reduces repetition. No issues found here.
129-156: Efficient registry push.Parallel push to the registry is well-organized, matching the parallel build strategy. No concerns with correctness.
158-228: Deployment steps are clear.Deploying the services in parallel to ECS for each component is a solid approach for quick rollouts. Logging and naming conventions are consistent. Looks good!
apiserver/plane/api/views/issue.py (1)
358-361: Confirmcreated_byassignment logic.The code only assigns
issue.created_by_idifissue.created_byisNone. Ensure all relevant calls pass a valid user ID or an override is not required. Otherwise, you might inadvertently miss logging the actual creator.Do you want a script to verify all usage of
issue.created_byand ensure consistent assignment throughout the codebase?apiserver/plane/authentication/views/app/magic.py (3)
65-70: Generate fallback emails carefully.Using
username + "@plane-shipsy.com"as a fallback is acceptable, but ensure thatusernameis always provided or validated. Otherwise, this could produce invalid email addresses ifusernameis empty or malformed.
79-79: Token in response is acceptable if ephemeral.Returning the
tokenin plain text suits a short-lived magic link approach, but confirm that each token is single-use or short-lived. Otherwise, consider rotating or securely storing it to mitigate replay attacks.
88-101: Workspace auto-creation logic is well-designed.Automatically adding the user and admin to the default workspace and project upon sign-in appears consistent with the product’s requirement. No issues found here.
|
|
||
| useEffect(() => { | ||
| console.log(pathname, 'pathname'); | ||
| window.parent.postMessage({ type: "ROUTE_CHANGE", path: pathname }, "*"); |
There was a problem hiding this comment.
Add origin verification to window messaging for security.
The current implementation accepts messages from any origin (*) and doesn't verify the source of incoming messages. This is a potential security vulnerability that could lead to cross-site scripting (XSS) attacks.
- window.parent.postMessage({ type: "ROUTE_CHANGE", path: pathname }, "*");
+ // Use a specific trusted origin instead of "*"
+ const trustedOrigin = process.env.NEXT_PUBLIC_TRUSTED_PARENT_ORIGIN || window.location.origin;
+ window.parent.postMessage({ type: "ROUTE_CHANGE", path: pathname }, trustedOrigin);And for the message handler:
const onIncomingMessage = async (event) => {
- console.log('onIncomingMessage', event);
+ // Verify the origin of the message
+ const trustedOrigin = process.env.NEXT_PUBLIC_TRUSTED_PARENT_ORIGIN || window.location.origin;
+ if (event.origin !== trustedOrigin) return;
+
if (event.data.type === "PLANE_SIGN_OUT") {
try {
await handleSignOut();
- window.parent.postMessage({ type: "PLANE_SIGN_OUT_SUCCESS", path: pathname }, "*");
+ window.parent.postMessage({ type: "PLANE_SIGN_OUT_SUCCESS", path: pathname }, trustedOrigin);
} catch (err) {}
}
};Also applies to: 58-65
| ] | ||
|
|
||
| def get_queryset(self): | ||
| print(self.kwargs.get("project_id")) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remove debug print statement before deploying to production.
The added print statement is likely for debugging purposes. Using a proper logging mechanism would be more appropriate in a production environment.
- print(self.kwargs.get("project_id"))
+ # Use Django's logging framework instead
+ import logging
+ logger = logging.getLogger(__name__)
+ logger.debug("Processing project_id: %s", self.kwargs.get("project_id"))📝 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.
| print(self.kwargs.get("project_id")) | |
| # Use Django's logging framework instead | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| logger.debug("Processing project_id: %s", self.kwargs.get("project_id")) |
| rm -rf $PLANE_TEMP_CODE_DIR | ||
| mkdir -p $PLANE_TEMP_CODE_DIR | ||
| REPO=https://github.com/makeplane/plane.git | ||
| REPO=https://github.com/shipsy/plane.git |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Repository URL has been changed to a different organization.
The repository URL has been changed from the original makeplane/plane.git to shipsy/plane.git. This change may have implications for maintenance, security updates, and compatibility.
Please confirm if this change is intentional and aligns with your deployment strategy. If this is a temporary change for development purposes, it should be reverted before merging to production.
Below is a shell script to search for both the legacy and new repository URLs across the repository and display the context around line 185 in deploy/selfhost/install.sh for further verification:
Please run this script to confirm whether the change from makeplane/plane.git to shipsy/plane.git is consistent throughout the codebase and intentional.
🏁 Script executed:
#!/bin/bash
# Search for the legacy repository URL in the entire repository
echo "Searching for legacy repository URL (https://github.com/makeplane/plane.git):"
rg "https://github.com/makeplane/plane.git" -n .
# Search for the new repository URL in the entire repository
echo "Searching for new repository URL (https://github.com/shipsy/plane.git):"
rg "https://github.com/shipsy/plane.git" -n .
# Display context around line 185 in the install.sh file
echo "Displaying context for deploy/selfhost/install.sh (lines 180-190):"
sed -n '180,190p' deploy/selfhost/install.shLength of output: 1345
Repository URL Change – Confirm Consistency Across the Codebase
The deployment script (deploy/selfhost/install.sh, line 185) now sets
REPO=https://github.com/shipsy/plane.git
which differs from the repository URL referenced in other files (e.g., package.json, README.md, and CONTRIBUTING.md still point to https://github.com/makeplane/plane.git). This inconsistency may lead to issues with clone operations, documentation accuracy, and overall maintenance.
- Confirm if the change to the new URL (
shipsy/plane.git) is an intentional part of a migration strategy. - If intentional, please update all references (including in documentation and configuration files) to ensure consistency.
- If the change was temporary or unintentional, revert the URL in the deployment script to match the legacy URL.
| ssl_cert_reqs=None, | ||
| ) | ||
| else: | ||
| print("redis url: ", settings.REDIS_URL) |
There was a problem hiding this comment.
Remove debug print statement containing potentially sensitive information.
Printing the Redis URL to console could expose sensitive connection details including passwords in logs. This is a security risk in production environments.
- print("redis url: ", settings.REDIS_URL)
+ # Use Django's logging framework with appropriate log level instead
+ import logging
+ logger = logging.getLogger(__name__)
+ # Log only the host, not the full URL with credentials
+ parsed_url = urlparse(settings.REDIS_URL)
+ logger.debug("Connecting to Redis at: %s:%s", parsed_url.hostname, parsed_url.port)Committable suggestion skipped: line range outside the PR's diff.
| "workspaces/<str:slug>/projects/<str:project_id>/archive/", | ||
| ProjectArchiveUnarchiveAPIEndpoint.as_view(), |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Ensure proper project_id validation
Changing from uuid:project_id to str:project_id removes automatic UUID format validation. Make sure that the ProjectArchiveUnarchiveAPIEndpoint view properly validates the format of incoming project IDs to maintain data integrity.
🏁 Script executed:
#!/bin/bash
# Check if the ProjectAPIEndpoint and ProjectArchiveUnarchiveAPIEndpoint contain validation for project IDs
echo "Checking validation in ProjectAPIEndpoint view:"
rg -A 10 "class ProjectAPIEndpoint" --type py
echo "Checking validation in ProjectArchiveUnarchiveAPIEndpoint view:"
rg -A 10 "class ProjectArchiveUnarchiveAPIEndpoint" --type py
echo "Looking for any UUID validation in these views:"
rg "UUID|uuid" -C 3 --type py apiserver/plane/api/views/project.pyLength of output: 1968
ProjectID Validation Missing in Archive Endpoint
Changing the URL parameter from uuid:project_id to str:project_id removes Django’s built-in UUID validation. Our verification confirms that neither ProjectArchiveUnarchiveAPIEndpoint nor related views explicitly validate that project_id adheres to UUID formatting before using it in database queries. This could lead to unexpected errors or security issues if malformed IDs are provided.
- Action Required: Explicitly validate the
project_id(for example, by using Python'sUUIDconversion with proper exception handling or a regex check) in thepostmethod ofProjectArchiveUnarchiveAPIEndpoint(located inapiserver/plane/api/views/project.py).
| export const FilterAdditionalProperties: React.FC<Props> = observer((props) => { | ||
| const { workspaceSlug, projectId } = useParams(); | ||
| const { appliedFilters, handleUpdate, searchQuery, additionalPropertyTitle, additionalPropertyKey } = props; | ||
| const workspaceService = new WorkspaceService(API_BASE_URL); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Potential type safety issue with useParams.
The component directly accesses workspaceSlug and projectId from useParams() without checking for null/undefined values, which could lead to runtime errors.
- const { workspaceSlug, projectId } = useParams();
+ const params = useParams();
+ const workspaceSlug = params?.workspaceSlug;
+ const projectId = params?.projectId;
+
+ if (!workspaceSlug || !projectId) {
+ return <p className="text-xs italic text-custom-text-400">Missing workspace or project information</p>;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const FilterAdditionalProperties: React.FC<Props> = observer((props) => { | |
| const { workspaceSlug, projectId } = useParams(); | |
| const { appliedFilters, handleUpdate, searchQuery, additionalPropertyTitle, additionalPropertyKey } = props; | |
| const workspaceService = new WorkspaceService(API_BASE_URL); | |
| export const FilterAdditionalProperties: React.FC<Props> = observer((props) => { | |
| const params = useParams(); | |
| const workspaceSlug = params?.workspaceSlug; | |
| const projectId = params?.projectId; | |
| if (!workspaceSlug || !projectId) { | |
| return <p className="text-xs italic text-custom-text-400">Missing workspace or project information</p>; | |
| } | |
| const { appliedFilters, handleUpdate, searchQuery, additionalPropertyTitle, additionalPropertyKey } = props; | |
| const workspaceService = new WorkspaceService(API_BASE_URL); | |
| // ... rest of the component logic | |
| }); |
| const handleCustomPropertiesUpdate = async (updatedProperties: CustomProperty[]) => { | ||
| try { | ||
| const updateRequests = updatedProperties.map((property) => { | ||
| const customPropertyId = property?.id || ""; | ||
| const apiUrl = `/api/v1/workspaces/${workspaceSlug}/issues/${issueId}/custom-properties/`; | ||
| if (customPropertyId) { | ||
| return axios.patch( | ||
| `${apiUrl}${customPropertyId}/`, | ||
| { value: property.value }, | ||
| { | ||
| headers: { | ||
| 'x-api-key': 'TEST_API_TOKEN', | ||
| 'Content-Type': 'application/json' | ||
| } | ||
| } | ||
| ); | ||
| } else { | ||
| return axios.post( | ||
| apiUrl, | ||
| { | ||
| key: property.key, | ||
| value: property.value, | ||
| issue_type_custom_property: property.issue_type_custom_property, | ||
| }, | ||
| { | ||
| headers: { | ||
| 'x-api-key': 'TEST_API_TOKEN', | ||
| 'Content-Type': 'application/json' | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| }); | ||
| await Promise.all(updateRequests); | ||
| } catch (error) { | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Handle caught errors appropriately.
The catch block is empty, which may hide issues during runtime. Add robust error logging or handling to make debugging easier.
Here is a suggested fix:
- } catch (error) {
- }
+ } catch (error) {
+ console.error("Failed to update custom properties:", error);
+ // Optionally, display an in-app notification or fallback UI here.
+ }📝 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.
| const handleCustomPropertiesUpdate = async (updatedProperties: CustomProperty[]) => { | |
| try { | |
| const updateRequests = updatedProperties.map((property) => { | |
| const customPropertyId = property?.id || ""; | |
| const apiUrl = `/api/v1/workspaces/${workspaceSlug}/issues/${issueId}/custom-properties/`; | |
| if (customPropertyId) { | |
| return axios.patch( | |
| `${apiUrl}${customPropertyId}/`, | |
| { value: property.value }, | |
| { | |
| headers: { | |
| 'x-api-key': 'TEST_API_TOKEN', | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| } else { | |
| return axios.post( | |
| apiUrl, | |
| { | |
| key: property.key, | |
| value: property.value, | |
| issue_type_custom_property: property.issue_type_custom_property, | |
| }, | |
| { | |
| headers: { | |
| 'x-api-key': 'TEST_API_TOKEN', | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| } | |
| }); | |
| await Promise.all(updateRequests); | |
| } catch (error) { | |
| } | |
| }; | |
| const handleCustomPropertiesUpdate = async (updatedProperties: CustomProperty[]) => { | |
| try { | |
| const updateRequests = updatedProperties.map((property) => { | |
| const customPropertyId = property?.id || ""; | |
| const apiUrl = `/api/v1/workspaces/${workspaceSlug}/issues/${issueId}/custom-properties/`; | |
| if (customPropertyId) { | |
| return axios.patch( | |
| `${apiUrl}${customPropertyId}/`, | |
| { value: property.value }, | |
| { | |
| headers: { | |
| 'x-api-key': 'TEST_API_TOKEN', | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| } else { | |
| return axios.post( | |
| apiUrl, | |
| { | |
| key: property.key, | |
| value: property.value, | |
| issue_type_custom_property: property.issue_type_custom_property, | |
| }, | |
| { | |
| headers: { | |
| 'x-api-key': 'TEST_API_TOKEN', | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| } | |
| }); | |
| await Promise.all(updateRequests); | |
| } catch (error) { | |
| console.error("Failed to update custom properties:", error); | |
| // Optionally, display an in-app notification or fallback UI here. | |
| } | |
| }; |
| def patch(self, request, slug, pk): | ||
| webhook = Webhook.objects.get(workspace__slug=slug, pk=pk) | ||
| serializer = WebhookSerializer( | ||
| webhook, | ||
| data=request.data, | ||
| context={request: request}, | ||
| partial=True, | ||
| fields=( | ||
| "id", | ||
| "url", | ||
| "is_active", | ||
| "created_at", | ||
| "updated_at", | ||
| "project", | ||
| "issue", | ||
| "cycle", | ||
| "module", | ||
| "issue_comment", | ||
| ), | ||
| ) | ||
| if serializer.is_valid(): | ||
| serializer.save() | ||
| return Response(serializer.data, status=status.HTTP_200_OK) | ||
| return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | ||
|
|
There was a problem hiding this comment.
Potential bug in serializer context.
At line 85, you’re passing context={request: request} instead of {"request": request}, causing the 'request' key to be the request object itself. This likely breaks the serializer’s logic. Proposed fix:
- context={request: request},
+ context={"request": request},📝 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.
| def patch(self, request, slug, pk): | |
| webhook = Webhook.objects.get(workspace__slug=slug, pk=pk) | |
| serializer = WebhookSerializer( | |
| webhook, | |
| data=request.data, | |
| context={request: request}, | |
| partial=True, | |
| fields=( | |
| "id", | |
| "url", | |
| "is_active", | |
| "created_at", | |
| "updated_at", | |
| "project", | |
| "issue", | |
| "cycle", | |
| "module", | |
| "issue_comment", | |
| ), | |
| ) | |
| if serializer.is_valid(): | |
| serializer.save() | |
| return Response(serializer.data, status=status.HTTP_200_OK) | |
| return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | |
| def patch(self, request, slug, pk): | |
| webhook = Webhook.objects.get(workspace__slug=slug, pk=pk) | |
| serializer = WebhookSerializer( | |
| webhook, | |
| data=request.data, | |
| context={"request": request}, | |
| partial=True, | |
| fields=( | |
| "id", | |
| "url", | |
| "is_active", | |
| "created_at", | |
| "updated_at", | |
| "project", | |
| "issue", | |
| "cycle", | |
| "module", | |
| "issue_comment", | |
| ), | |
| ) | |
| if serializer.is_valid(): | |
| serializer.save() | |
| return Response(serializer.data, status=status.HTTP_200_OK) | |
| return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) |
| echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production | ||
| pwd | ||
| mkdir -p apiserver/${configStoragePath} | ||
| echo "\${CONFIG}" > apiserver/${configStoragePath}/.env | ||
| """ | ||
|
|
||
| // Debugging: Show the contents of the .env file (optional for development only) | ||
| sh "cat apiserver/${configStoragePath}/.env" | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Avoid printing secrets to the console.
Currently, the pipeline prints the secret environment variable (CONFIG) via echo and also displays .env content explicitly for debugging. This is a security risk as it may expose secrets in CI logs. Consider removing or masking these prints in production to protect sensitive information.
-echo "Vault CONFIG: ${CONFIG}" # Debugging, remove in production
...
-cat apiserver/${configStoragePath}/.env
+echo "Vault CONFIG: [REDACTED]" # Secure alternative
...
+# Remove 'cat' command to avoid leaking secrets📝 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.
| echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production | |
| pwd | |
| mkdir -p apiserver/${configStoragePath} | |
| echo "\${CONFIG}" > apiserver/${configStoragePath}/.env | |
| """ | |
| // Debugging: Show the contents of the .env file (optional for development only) | |
| sh "cat apiserver/${configStoragePath}/.env" | |
| echo "Vault CONFIG: [REDACTED]" # Secure alternative | |
| pwd | |
| mkdir -p apiserver/${configStoragePath} | |
| echo "${CONFIG}" > apiserver/${configStoragePath}/.env | |
| """ | |
| // Debugging: Show the contents of the .env file (optional for development only) | |
| // Remove 'cat' command to avoid leaking secrets |
| current_instance = json.dumps(serializer.data, cls=DjangoJSONEncoder) | ||
| actor_id = str(request.user.id) if request.user else "Unknown" | ||
| issue_id_str = str(issue_id) if issue_id else "Unknown issue ID" | ||
| slug = slug=self.kwargs.get("slug") |
There was a problem hiding this comment.
Potential bug in slug assignment.
slug = slug=self.kwargs.get("slug") is redefining slug with a named parameter, which results in slug being assigned a tuple or leading to unexpected behavior. It should likely be slug = self.kwargs.get("slug").
-slug = slug=self.kwargs.get("slug")
+slug = self.kwargs.get("slug")📝 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.
| slug = slug=self.kwargs.get("slug") | |
| slug = self.kwargs.get("slug") |
Description
Type of Change
Screenshots and Media (if applicable)
Test Scenarios
References
Summary by CodeRabbit
New Features
Improvements