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-2630] chore: double click action added to draft issue and code refactor #5821

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 154 additions & 83 deletions web/core/components/issues/workspace-draft/draft-issue-block.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
"use client";
import React, { FC, useRef } from "react";
import React, { FC, useRef, useState } from "react";
import { omit } from "lodash";
import { observer } from "mobx-react";
import { Copy, Pencil, SquareStackIcon, Trash2 } from "lucide-react";
// types
import { TWorkspaceDraftIssue } from "@plane/types";
// ui
import { Row, Tooltip } from "@plane/ui";
import { Row, TContextMenuItem, Tooltip } from "@plane/ui";
// constants
import { EIssuesStoreType } from "@/constants/issue";
// helper
import { cn } from "@/helpers/common.helper";
// hooks
Expand All @@ -11,6 +17,8 @@ import { useAppTheme, useProject, useWorkspaceDraftIssues } from "@/hooks/store"
import { IdentifierText, IssueTypeIdentifier } from "@/plane-web/components/issues";
// local components
import { WorkspaceDraftIssueQuickActions } from "../issue-layouts";
import { CreateUpdateIssueModal } from "../issue-modal";
import { WorkspaceDraftIssueDeleteIssueModal } from "./delete-modal";
import { DraftIssueProperties } from "./draft-issue-properties";

type Props = {
Expand All @@ -21,8 +29,13 @@ type Props = {
export const DraftIssueBlock: FC<Props> = observer((props) => {
// props
const { workspaceSlug, issueId } = props;
// states
const [moveToIssue, setMoveToIssue] = useState(false);
const [createUpdateIssueModal, setCreateUpdateIssueModal] = useState(false);
const [issueToEdit, setIssueToEdit] = useState<TWorkspaceDraftIssue | undefined>(undefined);
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
// hooks
const { getIssueById, updateIssue, deleteIssue, moveIssue } = useWorkspaceDraftIssues();
const { getIssueById, updateIssue, deleteIssue } = useWorkspaceDraftIssues();
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

Include createIssue in the imports from useWorkspaceDraftIssues

To enable creating new issues when issueToEdit is undefined, import createIssue from useWorkspaceDraftIssues.

Apply this diff:

- const { getIssueById, updateIssue, deleteIssue } = useWorkspaceDraftIssues();
+ const { getIssueById, updateIssue, deleteIssue, createIssue } = useWorkspaceDraftIssues();
📝 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
const { getIssueById, updateIssue, deleteIssue } = useWorkspaceDraftIssues();
const { getIssueById, updateIssue, deleteIssue, createIssue } = useWorkspaceDraftIssues();

const { sidebarCollapsed: isSidebarCollapsed } = useAppTheme();
const { getProjectIdentifierById } = useProject();
// ref
Expand All @@ -32,97 +45,155 @@ export const DraftIssueBlock: FC<Props> = observer((props) => {
const projectIdentifier = (issue && issue.project_id && getProjectIdentifierById(issue.project_id)) || undefined;
if (!issue || !projectIdentifier) return null;

const duplicateIssuePayload = omit(
{
...issue,
name: `${issue.name} (copy)`,
is_draft: true,
},
["id"]
);

const MENU_ITEMS: TContextMenuItem[] = [
{
key: "edit",
title: "Edit",
icon: Pencil,
action: () => {
setIssueToEdit(issue);
setCreateUpdateIssueModal(true);
},
},
Comment on lines +63 to +66
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

Extract repeated code into a separate function for reusability

The action logic here is duplicated in the onDoubleClick handler. Consider extracting this logic into a separate function to promote reusability and reduce code duplication.

Apply this diff:

+ const handleEditIssue = () => {
+   setIssueToEdit(issue);
+   setCreateUpdateIssueModal(true);
+ };
...
{
  key: "edit",
  title: "Edit",
  icon: Pencil,
  action: () => {
-   setIssueToEdit(issue);
-   setCreateUpdateIssueModal(true);
+   handleEditIssue();
  },
},

Committable suggestion was skipped due to low confidence.

{
key: "make-a-copy",
title: "Make a copy",
icon: Copy,
action: () => {
setCreateUpdateIssueModal(true);
},
},
{
key: "move-to-issues",
title: "Move to issues",
icon: SquareStackIcon,
action: () => {
setMoveToIssue(true);
setIssueToEdit(issue);
setCreateUpdateIssueModal(true);
},
},
{
key: "delete",
title: "Delete",
icon: Trash2,
action: () => {
setDeleteIssueModal(true);
},
},
];

return (
<div id={`issue-${issue.id}`} className=" relative border-b border-b-custom-border-200 w-full cursor-pointer">
<Row
ref={issueRef}
className={cn(
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 py-3 text-sm transition-colors border border-transparent last:border-b-transparent",
{
"md:flex-row md:items-center": isSidebarCollapsed,
"lg:flex-row lg:items-center": !isSidebarCollapsed,
}
)}
<>
<WorkspaceDraftIssueDeleteIssueModal
data={issue}
isOpen={deleteIssueModal}
handleClose={() => setDeleteIssueModal(false)}
onSubmit={async () => deleteIssue(workspaceSlug, issueId)}
/>
<CreateUpdateIssueModal
isOpen={createUpdateIssueModal}
onClose={() => {
setCreateUpdateIssueModal(false);
setIssueToEdit(undefined);
setMoveToIssue(false);
}}
data={issueToEdit ?? duplicateIssuePayload}
onSubmit={async (data) => {
if (issueToEdit) await updateIssue(workspaceSlug, issueId, data);
}}
storeType={EIssuesStoreType.WORKSPACE_DRAFT}
Comment on lines +111 to +114
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

Add logic to handle creation of new issues in the onSubmit handler

Currently, the onSubmit handler only updates an issue when issueToEdit is defined. When making a copy or creating a new issue, issueToEdit is undefined, and no action is taken. Add logic to create a new issue when issueToEdit is undefined.

Apply this diff:

onSubmit={async (data) => {
  if (issueToEdit) {
    await updateIssue(workspaceSlug, issueId, data);
  }
+ else {
+   await createIssue(workspaceSlug, data);
+ }
}}
📝 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
onSubmit={async (data) => {
if (issueToEdit) await updateIssue(workspaceSlug, issueId, data);
}}
storeType={EIssuesStoreType.WORKSPACE_DRAFT}
onSubmit={async (data) => {
if (issueToEdit) {
await updateIssue(workspaceSlug, issueId, data);
}
else {
await createIssue(workspaceSlug, data);
}
}}
storeType={EIssuesStoreType.WORKSPACE_DRAFT}

fetchIssueDetails={false}
moveToIssue={moveToIssue}
isDraft
/>
<div
id={`issue-${issue.id}`}
className=" relative border-b border-b-custom-border-200 w-full cursor-pointer"
onDoubleClick={() => {
setIssueToEdit(issue);
setCreateUpdateIssueModal(true);
}}
>
Comment on lines +123 to 126
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

Reuse the extracted function for handling issue editing

After extracting the common logic, use the new handleEditIssue function here to maintain consistency and reduce duplication.

Apply this diff:

onDoubleClick={() => {
- setIssueToEdit(issue);
- setCreateUpdateIssueModal(true);
+ handleEditIssue();
}}

Committable suggestion was skipped due to low confidence.

<div className="flex w-full truncate">
<div className="flex flex-grow items-center gap-0.5 truncate">
<div className="flex items-center gap-1">
{/* {displayProperties && (displayProperties.key || displayProperties.issue_type) && ( */}
<div className="flex-shrink-0">
{issue.project_id && (
<div className="flex items-center space-x-2">
{issue?.type_id && <IssueTypeIdentifier issueTypeId={issue.type_id} />}
<IdentifierText
identifier={projectIdentifier}
enableClickToCopyIdentifier
textContainerClassName="text-xs font-medium text-custom-text-300"
/>
</div>
)}
<Row
ref={issueRef}
className={cn(
"group/list-block min-h-11 relative flex flex-col gap-3 bg-custom-background-100 hover:bg-custom-background-90 py-3 text-sm transition-colors border border-transparent last:border-b-transparent",
{
"md:flex-row md:items-center": isSidebarCollapsed,
"lg:flex-row lg:items-center": !isSidebarCollapsed,
}
)}
>
<div className="flex w-full truncate">
<div className="flex flex-grow items-center gap-0.5 truncate">
<div className="flex items-center gap-1">
<div className="flex-shrink-0">
{issue.project_id && (
<div className="flex items-center space-x-2">
{issue?.type_id && <IssueTypeIdentifier issueTypeId={issue.type_id} />}
<IdentifierText
identifier={projectIdentifier}
enableClickToCopyIdentifier
textContainerClassName="text-xs font-medium text-custom-text-300"
/>
</div>
)}
</div>

{/* sub-issues chevron */}
<div className="size-4 grid place-items-center flex-shrink-0" />
</div>
{/* )} */}

{/* sub-issues chevron */}
<div className="size-4 grid place-items-center flex-shrink-0" />
<Tooltip tooltipContent={issue.name} position="top-left" renderByDefault={false}>
<p className="w-full truncate cursor-pointer text-sm text-custom-text-100">{issue.name}</p>
</Tooltip>
</div>

<Tooltip
tooltipContent={issue.name}
// isMobile={isMobile}
position="top-left"
// disabled={isCurrentBlockDragging}
renderByDefault={false}
{/* quick actions */}
<div
className={cn("block border border-custom-border-300 rounded", {
"md:hidden": isSidebarCollapsed,
"lg:hidden": !isSidebarCollapsed,
})}
>
<p className="w-full truncate cursor-pointer text-sm text-custom-text-100">{issue.name}</p>
</Tooltip>
</div>

{/* quick actions */}
<div
className={cn("block border border-custom-border-300 rounded", {
"md:hidden": isSidebarCollapsed,
"lg:hidden": !isSidebarCollapsed,
})}
>
<WorkspaceDraftIssueQuickActions
parentRef={issueRef}
issue={issue}
handleUpdate={async (data) => updateIssue(workspaceSlug, issueId, data)}
handleDelete={async () => deleteIssue(workspaceSlug, issueId)}
handleMoveToIssues={async () => moveIssue(workspaceSlug, issueId, issue)}
/>
<WorkspaceDraftIssueQuickActions parentRef={issueRef} MENU_ITEMS={MENU_ITEMS} />
</div>
</div>
</div>

<div className="flex flex-shrink-0 items-center gap-2">
<DraftIssueProperties
className={`relative flex flex-wrap ${isSidebarCollapsed ? "md:flex-grow md:flex-shrink-0" : "lg:flex-grow lg:flex-shrink-0"} items-center gap-2 whitespace-nowrap`}
issue={issue}
updateIssue={async (projectId, issueId, data) => {
await updateIssue(workspaceSlug, issueId, data);
}}
activeLayout="List"
/>
<div
className={cn("hidden", {
"md:flex": isSidebarCollapsed,
"lg:flex": !isSidebarCollapsed,
})}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<WorkspaceDraftIssueQuickActions
parentRef={issueRef}
<div className="flex flex-shrink-0 items-center gap-2">
<DraftIssueProperties
className={`relative flex flex-wrap ${isSidebarCollapsed ? "md:flex-grow md:flex-shrink-0" : "lg:flex-grow lg:flex-shrink-0"} items-center gap-2 whitespace-nowrap`}
issue={issue}
handleUpdate={async (data) => updateIssue(workspaceSlug, issueId, data)}
handleDelete={async () => deleteIssue(workspaceSlug, issueId)}
handleMoveToIssues={async () => moveIssue(workspaceSlug, issueId, issue)}
updateIssue={async (projectId, issueId, data) => {
await updateIssue(workspaceSlug, issueId, data);
}}
activeLayout="List"
/>
<div
className={cn("hidden", {
"md:flex": isSidebarCollapsed,
"lg:flex": !isSidebarCollapsed,
})}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<WorkspaceDraftIssueQuickActions parentRef={issueRef} MENU_ITEMS={MENU_ITEMS} />
</div>
</div>
</div>
</Row>
</div>
</Row>
</div>
</>
);
});
Loading
Loading