-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||||||||||||||||||||||||||||
|
@@ -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 = { | ||||||||||||||||||||||||||||
|
@@ -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(); | ||||||||||||||||||||||||||||
const { sidebarCollapsed: isSidebarCollapsed } = useAppTheme(); | ||||||||||||||||||||||||||||
const { getProjectIdentifierById } = useProject(); | ||||||||||||||||||||||||||||
// ref | ||||||||||||||||||||||||||||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Apply this diff: + const handleEditIssue = () => {
+ setIssueToEdit(issue);
+ setCreateUpdateIssueModal(true);
+ };
...
{
key: "edit",
title: "Edit",
icon: Pencil,
action: () => {
- setIssueToEdit(issue);
- setCreateUpdateIssueModal(true);
+ handleEditIssue();
},
},
|
||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add logic to handle creation of new issues in the Currently, the Apply this diff: onSubmit={async (data) => {
if (issueToEdit) {
await updateIssue(workspaceSlug, issueId, data);
}
+ else {
+ await createIssue(workspaceSlug, data);
+ }
}} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Apply this diff: onDoubleClick={() => {
- setIssueToEdit(issue);
- setCreateUpdateIssueModal(true);
+ handleEditIssue();
}}
|
||||||||||||||||||||||||||||
<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> | ||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include
createIssue
in the imports fromuseWorkspaceDraftIssues
To enable creating new issues when
issueToEdit
is undefined, importcreateIssue
fromuseWorkspaceDraftIssues
.Apply this diff:
📝 Committable suggestion