Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WEB-2388] fix: workspace draft issues #5800

Merged
merged 7 commits into from
Oct 11, 2024
Merged

Conversation

anmolsinghbhatia
Copy link
Collaborator

@anmolsinghbhatia anmolsinghbhatia commented Oct 11, 2024

Summary:
This PR included bug fixes and improvement for workspace draft issues.

Summary by CodeRabbit

  • New Features

    • Added fields type_id and description_html to draft issue serializers for enhanced data representation.
    • Introduced CountChip component to display the count of draft issues in the header.
  • Bug Fixes

    • Removed local storage functionality for draft issues to streamline saving processes.
  • Refactor

    • Updated logic in various components to improve data flow and interactivity related to draft issues.
  • Documentation

    • Enhanced comments and structure for better understanding of the new features and changes.

Copy link
Contributor

coderabbitai bot commented Oct 11, 2024

Walkthrough

The changes in this pull request encompass updates to several components and serializers related to draft issues within the application. Key modifications include the addition of new fields in the DraftIssueSerializer and DraftIssueDetailSerializer, enhancements to the WorkspaceDraftHeader component for displaying draft issue counts, and the removal of local storage functionality in the CreateUpdateIssueModalBase. Additionally, various hooks and properties have been updated in the issue store classes to improve data handling and interactivity.

Changes

File Path Change Summary
apiserver/plane/app/serializers/draft.py - Added fields type_id and description_html to DraftIssueSerializer.
- Updated read_only_fields to include all fields.
- Explicitly included description_html in DraftIssueDetailSerializer.
web/app/[workspaceSlug]/(projects)/drafts/header.tsx - Added CountChip component to display draft issue count.
- Integrated useWorkspaceDraftIssues hook for pagination info.
web/core/components/issues/issue-modal/base.tsx - Removed local storage functionality for draft issues.
- Updated handleClose and handleFormSubmit methods.
web/core/components/issues/issue-modal/draft-issue-layout.tsx - Updated imports to include useWorkspaceDraftIssues.
- Modified handleCreateDraftIssue to use createIssue from the new hook.
web/core/components/issues/workspace-draft/root.tsx - Updated imports to include additional hooks.
- Altered destructured return values from useWorkspaceDraftIssues.
- Added conditional rendering for EmptyState component.
web/core/store/issue/root.store.ts - Updated constructors of WorkspaceDraftIssues, DraftIssues, and CalendarStore to accept this.
web/core/store/issue/workspace-draft/issue.store.ts - Added new observable property issueMapIds.
- Updated constructor to accept issueStore.
- Refactored issueIds and modified action methods.

Possibly related PRs

Suggested labels

🐛bug, ⚙️backend

Suggested reviewers

  • rahulramesha
  • sriramveeraghanta

Poem

In the meadow where drafts take flight,
New fields emerge, a wondrous sight.
With counts displayed, our header shines,
No more lost drafts in storage confines.
Hops of joy as issues align,
Together we craft, our work divine! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (8)
web/app/[workspaceSlug]/(projects)/drafts/header.tsx (2)

40-48: LGTM: UI enhancement with draft issue count.

The addition of the CountChip component improves the UI by displaying the count of draft issues. The conditional rendering is implemented correctly.

Consider a minor optimization to simplify the conditional rendering:

-            {paginationInfo?.count && paginationInfo?.count > 0 ? <CountChip count={paginationInfo?.count} /> : <></>}
+            {paginationInfo?.count > 0 && <CountChip count={paginationInfo.count} />}

This change removes the redundant check and empty fragment, making the code more concise.


Line range hint 1-65: Overall changes look good and align with PR objectives.

The WorkspaceDraftHeader component has been successfully updated to include the count of draft issues. The changes are well-integrated, maintaining the existing structure while adding new functionality. The use of hooks and conditional rendering is appropriate and consistent with React best practices.

As the component grows in complexity, consider breaking it down into smaller, more focused components in the future. This will improve maintainability and reusability.

web/core/components/issues/issue-modal/draft-issue-layout.tsx (2)

56-56: LGTM: New hook useWorkspaceDraftIssues utilized

The usage of createIssue from useWorkspaceDraftIssues is a good implementation of the newly imported hook. This change aligns well with the modifications in the handleCreateDraftIssue function.

Consider renaming the destructured function to createDraftIssue for better clarity:

const { createIssue: createDraftIssue } = useWorkspaceDraftIssues();

This would make it more explicit that we're dealing with draft issues throughout the component.


Line range hint 98-130: LGTM: handleCreateDraftIssue updated to use new hook

The modification of handleCreateDraftIssue to use createIssue from the useWorkspaceDraftIssues hook is a good change. It maintains the existing functionality while leveraging the new hook-based approach.

Consider enhancing the error handling by logging the error or providing more specific error messages:

.catch((error) => {
  console.error("Failed to create draft issue:", error);
  setToast({
    type: TOAST_TYPE.ERROR,
    title: "Error!",
    message: `Issue could not be created: ${error.message || "Please try again."}`,
  });
  // ... rest of the error handling
});

This would provide more detailed information for debugging and potentially give users more context about the error.

apiserver/plane/app/serializers/draft.py (2)

279-280: LGTM! Consider adding docstring for new fields.

The addition of type_id and description_html to the DraftIssueSerializer is appropriate and consistent with the existing pattern. These fields enhance the serializer's capability to handle issue types and HTML-formatted descriptions.

Consider adding a docstring to the DraftIssueSerializer class to explain the purpose of these new fields, especially type_id, as it might not be immediately clear to other developers what type of issue it represents.

class DraftIssueSerializer(BaseSerializer):
    """
    Serializer for draft issues.

    Fields:
    - type_id: Represents the type of the issue (e.g., bug, feature, task).
    - description_html: HTML-formatted description of the issue.
    ...
    """
    # ... rest of the code

Line range hint 288-291: Remove redundant field declaration.

The description_html field is already inherited from DraftIssueSerializer. Explicitly adding it to the fields list in DraftIssueDetailSerializer is redundant and might cause confusion.

Consider removing the redundant field declaration:

class DraftIssueDetailSerializer(DraftIssueSerializer):
    description_html = serializers.CharField()

    class Meta(DraftIssueSerializer.Meta):
-        fields = DraftIssueSerializer.Meta.fields + [
-            "description_html",
-        ]
+        fields = DraftIssueSerializer.Meta.fields
        read_only_fields = fields

This change will maintain the same functionality while reducing redundancy in the code.

web/core/components/issues/issue-modal/base.tsx (2)

Line range hint 126-133: LGTM with a minor suggestion.

The refactoring of the handleClose function looks good. It simplifies the logic by removing local storage handling and directly calling handleCreateIssue when necessary. This aligns well with the removal of local storage functionality for draft issues.

Consider renaming the saveAsDraft parameter to shouldSaveAsDraft for better clarity:

-const handleClose = (saveAsDraft?: boolean) => {
-  if (changesMade && saveAsDraft && !data) {
+const handleClose = (shouldSaveAsDraft?: boolean) => {
+  if (changesMade && shouldSaveAsDraft && !data) {

This small change would make the parameter's purpose more explicit.


Line range hint 261-263: LGTM with a minor suggestion for improved clarity.

The removal of sourceIssueId from the payload is a good cleanup step. It ensures that this temporary property doesn't persist in the created or updated issue.

To improve code clarity, consider using the optional chaining operator:

-if (data?.sourceIssueId) delete data.sourceIssueId;
+delete data?.sourceIssueId;

This change simplifies the code while maintaining the same functionality, as delete is safe to use on non-existent properties.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 2c96e04 and 96bd3d7.

📒 Files selected for processing (7)
  • apiserver/plane/app/serializers/draft.py (1 hunks)
  • web/app/[workspaceSlug]/(projects)/drafts/header.tsx (3 hunks)
  • web/core/components/issues/issue-modal/base.tsx (2 hunks)
  • web/core/components/issues/issue-modal/draft-issue-layout.tsx (3 hunks)
  • web/core/components/issues/workspace-draft/root.tsx (4 hunks)
  • web/core/store/issue/root.store.ts (2 hunks)
  • web/core/store/issue/workspace-draft/issue.store.ts (8 hunks)
🧰 Additional context used
🔇 Additional comments (18)
web/app/[workspaceSlug]/(projects)/drafts/header.tsx (2)

9-9: LGTM: New imports are correctly added.

The new imports for CountChip and useWorkspaceDraftIssues are correctly placed and consistent with the changes described in the summary.

Also applies to: 14-14


23-23: LGTM: New hook is correctly used.

The useWorkspaceDraftIssues hook is correctly implemented to retrieve the paginationInfo.

To ensure the hook is implemented correctly, you may want to verify its implementation. Here's a script to check the hook's definition:

✅ Verification successful

Verified: Hook implementation is correct.

The useWorkspaceDraftIssues hook is correctly implemented to retrieve the paginationInfo.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of useWorkspaceDraftIssues hook

# Test: Search for the hook definition
ast-grep --lang typescript --pattern 'export const useWorkspaceDraftIssues = $_'

Length of output: 763

web/core/components/issues/issue-modal/draft-issue-layout.tsx (2)

17-17: LGTM: Import statement updated to include useWorkspaceDraftIssues

The addition of useWorkspaceDraftIssues from @/hooks/store is a good change. It suggests a move towards using a custom hook for managing draft issues, which can lead to better code organization and reusability.


Line range hint 1-158: Overall assessment: Good improvements in code organization

The changes in this file represent a positive step towards better code organization and potential reusability. By introducing the useWorkspaceDraftIssues hook and updating the handleCreateDraftIssue function to use it, the component now delegates the draft issue creation logic to a dedicated hook. This approach can lead to more maintainable and testable code.

The modifications are well-integrated into the existing component structure, maintaining its overall functionality while improving its implementation. The consistent use of the new hook throughout the component shows good attention to detail.

These changes are approved and ready for merging, pending the minor suggestions made in previous comments.

web/core/store/issue/root.store.ts (3)

206-206: LGTM: WorkspaceDraftIssues initialization updated

The change to pass this to the WorkspaceDraftIssues constructor is consistent with other store initializations and aligns with the PR objectives related to workspace draft issues. This update allows WorkspaceDraftIssues to access the IssueRootStore context, which can improve data flow and interactivity.


227-227: Verify the need for CalendarStore update

The change to pass this to the CalendarStore constructor is consistent with other store initializations. However, this change wasn't explicitly mentioned in the PR objectives related to workspace draft issues.

Could you please confirm if this change is intentional and necessary for the current PR objectives? If it's related to a different feature or improvement, consider splitting it into a separate PR for better traceability.


Line range hint 1-229: Overall assessment: Minor improvements to store initializations

The changes in this file are minimal and focused on improving the consistency of store initializations. They potentially enhance data flow between stores by providing access to the IssueRootStore context. The WorkspaceDraftIssues change aligns well with the PR objectives. However, the CalendarStore change, while consistent with the pattern, might benefit from additional context or justification if it's not directly related to the current PR objectives.

apiserver/plane/app/serializers/draft.py (1)

Line range hint 1-291: Overall, the changes improve the draft issue serializers.

The additions to DraftIssueSerializer and DraftIssueDetailSerializer enhance their capabilities to handle issue types and HTML-formatted descriptions. The changes are consistent with the existing code structure and don't introduce any major issues.

A few minor improvements have been suggested:

  1. Adding a docstring to DraftIssueSerializer to explain the new fields.
  2. Removing a redundant field declaration in DraftIssueDetailSerializer.

These changes will improve code clarity and maintainability without affecting functionality.

web/core/components/issues/issue-modal/base.tsx (1)

321-321: LGTM: Improved prop passing.

The update to directly pass handleClose as the onClose prop is a good improvement. It simplifies the code by removing an unnecessary anonymous function wrapper, which enhances readability and potentially improves performance by avoiding the creation of a new function on each render.

web/core/components/issues/workspace-draft/root.tsx (1)

28-28: Handle potential undefined return from useProject hook

Ensure that the useProject hook returns a defined workspaceProjectIds. If there's a possibility that workspaceProjectIds could be null or undefined, it might be beneficial to set a default value to prevent potential runtime errors.

Run the following script to check if workspaceProjectIds can be undefined:

web/core/store/issue/workspace-draft/issue.store.ts (8)

27-28: Importing IIssueRootStore

The addition of IIssueRootStore import from "../root.store" is appropriate for injecting the root issue store into WorkspaceDraftIssues.


35-37: Adding issueMapIds to the interface

Including issueMapIds in the IWorkspaceDraftIssues interface enhances the tracking of issue IDs per workspace, promoting better data organization.


119-123: Initialize issueMapIds and inject issueStore

Initializing issueMapIds and injecting issueStore through the constructor improves state management and ensures access to the workspace slug.


126-126: Making issueMapIds observable

Adding issueMapIds to the observable properties ensures that any changes to the issue ID mappings are properly tracked and reacted to within the application.

Also applies to: 128-128


144-148: Compute issueIds based on current workspace

The issueIds computed property correctly retrieves and orders issue IDs for the current workspace by creation date in descending order.


225-228: Update issueMapIds after fetching issues

Upon fetching issues, updating issueMapIds with the new issue IDs maintains the mapping between workspace slugs and their corresponding issue IDs.


252-255: Add new issue to issueMapIds after creation

In the createIssue method, adding the new issue ID to the beginning of issueMapIds ensures that the most recently created issues appear first.


271-275: Update issue in issuesMap with new data

The updateIssue method correctly merges the existing issue data with the new payload and updates the updated_at timestamp.


{paginationInfo?.next_page_results && (
<Fragment>
{loader === "pagination" && issueIds.length >= 0 ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify conditional rendering by removing redundant check

The condition issueIds.length >= 0 at line 70 is always true because an array's length is always greater than or equal to zero. You can simplify the conditional rendering by removing this redundant check.

Apply this diff to simplify the condition:

-          {loader === "pagination" && issueIds.length >= 0 ? (
+          {loader === "pagination" ? (
📝 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.

Suggested change
{loader === "pagination" && issueIds.length >= 0 ? (
{loader === "pagination" ? (

Comment on lines +47 to +57
if (workspaceProjectIds?.length === 0)
return (
<EmptyState
type={EmptyStateType.WORKSPACE_NO_PROJECTS}
size="sm"
primaryButtonOnClick={() => {
toggleCreateProjectModal(true);
}}
/>
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure proper handling when workspaceProjectIds is undefined

At line 47, the condition workspaceProjectIds?.length === 0 checks for an empty array. However, if workspaceProjectIds is undefined, workspaceProjectIds?.length will be undefined, and the condition will evaluate to false. If you intend to show the EmptyState when workspaceProjectIds is undefined or empty, consider updating the condition.

Apply this diff to handle both undefined and empty arrays:

-  if (workspaceProjectIds?.length === 0)
+  if (!workspaceProjectIds || workspaceProjectIds.length === 0)
📝 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.

Suggested change
if (workspaceProjectIds?.length === 0)
return (
<EmptyState
type={EmptyStateType.WORKSPACE_NO_PROJECTS}
size="sm"
primaryButtonOnClick={() => {
toggleCreateProjectModal(true);
}}
/>
);
if (!workspaceProjectIds || workspaceProjectIds.length === 0)
return (
<EmptyState
type={EmptyStateType.WORKSPACE_NO_PROJECTS}
size="sm"
primaryButtonOnClick={() => {
toggleCreateProjectModal(true);
}}
/>
);

Comment on lines +69 to +86
<Fragment>
{loader === "pagination" && issueIds.length >= 0 ? (
<WorkspaceDraftIssuesLoader items={1} />
) : (
<div
className={cn(
"h-11 pl-6 p-3 text-sm font-medium bg-custom-background-100 border-b border-custom-border-200 transition-all",
{
"text-custom-primary-100 hover:text-custom-primary-200 cursor-pointer underline-offset-2 hover:underline":
paginationInfo?.next_page_results,
}
)}
onClick={handleNextIssues}
>
Load More &darr;
</div>
)}
onClick={handleNextIssues}
>
Load More &darr;
</div>
</Fragment>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider removing unnecessary Fragment wrapper

The <Fragment> wrapper introduced at lines 69 to 86 is unnecessary since it only contains a single child element. You can remove the Fragment to simplify the code.

Apply this diff to remove the Fragment:

{paginationInfo?.next_page_results && (
-  <Fragment>
    {loader === "pagination" ? (
      <WorkspaceDraftIssuesLoader items={1} />
    ) : (
      <div
        className={cn(
          "h-11 pl-6 p-3 text-sm font-medium bg-custom-background-100 border-b border-custom-border-200 transition-all",
          {
            "text-custom-primary-100 hover:text-custom-primary-200 cursor-pointer underline-offset-2 hover:underline":
              paginationInfo?.next_page_results,
          }
        )}
        onClick={handleNextIssues}
      >
        Load More &darr;
      </div>
    )}
-  </Fragment>
)}

Since Fragment is no longer used elsewhere, you can also remove the import statement at line 3:

-import { FC, Fragment } from "react";
+import { FC } from "react";

Committable suggestion was skipped due to low confidence.

Comment on lines +312 to +315
runInAction(() => {
unset(this.issueMapIds[workspaceSlug], issueId);
unset(this.issuesMap, issueId);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix issue removal in moveIssue: incorrect use of unset on arrays

Similar to deleteIssue, the moveIssue method incorrectly uses unset on an array to remove an issueId. This does not effectively remove the issue ID from the list.

Suggested fix:

runInAction(() => {
-  unset(this.issueMapIds[workspaceSlug], issueId);
+  update(this.issueMapIds, [workspaceSlug], (issueIds = []) => issueIds.filter(id => id !== issueId));
   unset(this.issuesMap, issueId);
});
📝 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.

Suggested change
runInAction(() => {
unset(this.issueMapIds[workspaceSlug], issueId);
unset(this.issuesMap, issueId);
});
runInAction(() => {
update(this.issueMapIds, [workspaceSlug], (issueIds = []) => issueIds.filter(id => id !== issueId));
unset(this.issuesMap, issueId);
});

Comment on lines +294 to +297
runInAction(() => {
unset(this.issueMapIds[workspaceSlug], issueId);
unset(this.issuesMap, issueId);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix issue removal: incorrect use of unset on arrays

The deleteIssue method uses unset on an array, which does not remove the issueId as intended. Since issueMapIds[workspaceSlug] is an array, you should remove the issueId using array manipulation methods.

Suggested fix:

runInAction(() => {
-  unset(this.issueMapIds[workspaceSlug], issueId);
+  update(this.issueMapIds, [workspaceSlug], (issueIds = []) => issueIds.filter(id => id !== issueId));
   unset(this.issuesMap, issueId);
});
📝 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.

Suggested change
runInAction(() => {
unset(this.issueMapIds[workspaceSlug], issueId);
unset(this.issuesMap, issueId);
});
runInAction(() => {
update(this.issueMapIds, [workspaceSlug], (issueIds = []) => issueIds.filter(id => id !== issueId));
unset(this.issuesMap, issueId);
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants