mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-1517] chore: remove drag handle from list drag block (#4698)
* remove drag handle from list drag block * align list group header with list item * rearrange chevron for list subissues and rearrange spaces * adding default draggable property to control link * remove unnecessary dependencies for useEffect
This commit is contained in:
parent
93a22034bd
commit
52d8d6e7ce
@ -7,10 +7,11 @@ export type TControlLink = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|||||||
target?: string;
|
target?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
draggable?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ControlLink = React.forwardRef<HTMLAnchorElement, TControlLink>((props, ref) => {
|
export const ControlLink = React.forwardRef<HTMLAnchorElement, TControlLink>((props, ref) => {
|
||||||
const { href, onClick, children, target = "_self", disabled = false, className, ...rest } = props;
|
const { href, onClick, children, target = "_self", disabled = false, className, draggable = false, ...rest } = props;
|
||||||
const LEFT_CLICK_EVENT_CODE = 0;
|
const LEFT_CLICK_EVENT_CODE = 0;
|
||||||
|
|
||||||
const handleOnClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
const handleOnClick = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
||||||
@ -33,7 +34,15 @@ export const ControlLink = React.forwardRef<HTMLAnchorElement, TControlLink>((pr
|
|||||||
if (disabled) return <>{children}</>;
|
if (disabled) return <>{children}</>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a href={href} target={target} onClick={handleOnClick} {...rest} ref={ref} className={className}>
|
<a
|
||||||
|
href={href}
|
||||||
|
target={target}
|
||||||
|
onClick={handleOnClick}
|
||||||
|
{...rest}
|
||||||
|
ref={ref}
|
||||||
|
className={className}
|
||||||
|
draggable={draggable}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,7 @@ import { ChevronRight } from "lucide-react";
|
|||||||
// types
|
// types
|
||||||
import { TIssue, IIssueDisplayProperties, TIssueMap } from "@plane/types";
|
import { TIssue, IIssueDisplayProperties, TIssueMap } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { Spinner, Tooltip, ControlLink, DragHandle } from "@plane/ui";
|
import { Spinner, Tooltip, ControlLink, setToast, TOAST_TYPE } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { MultipleSelectEntityAction } from "@/components/core";
|
import { MultipleSelectEntityAction } from "@/components/core";
|
||||||
import { IssueProperties } from "@/components/issues/issue-layouts/properties";
|
import { IssueProperties } from "@/components/issues/issue-layouts/properties";
|
||||||
@ -57,7 +57,6 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
} = props;
|
} = props;
|
||||||
// ref
|
// ref
|
||||||
const issueRef = useRef<HTMLDivElement | null>(null);
|
const issueRef = useRef<HTMLDivElement | null>(null);
|
||||||
const dragHandleRef = useRef(null);
|
|
||||||
// hooks
|
// hooks
|
||||||
const { workspaceSlug, projectId } = useAppRouter();
|
const { workspaceSlug, projectId } = useAppRouter();
|
||||||
const { getProjectIdentifierById } = useProject();
|
const { getProjectIdentifierById } = useProject();
|
||||||
@ -78,14 +77,12 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const element = issueRef.current;
|
const element = issueRef.current;
|
||||||
const dragHandleElement = dragHandleRef.current;
|
|
||||||
|
|
||||||
if (!element || !dragHandleElement) return;
|
if (!element) return;
|
||||||
|
|
||||||
return combine(
|
return combine(
|
||||||
draggable({
|
draggable({
|
||||||
element,
|
element,
|
||||||
dragHandle: dragHandleElement,
|
|
||||||
canDrag: () => canDrag,
|
canDrag: () => canDrag,
|
||||||
getInitialData: () => ({ id: issueId, type: "ISSUE", groupId }),
|
getInitialData: () => ({ id: issueId, type: "ISSUE", groupId }),
|
||||||
onDragStart: () => {
|
onDragStart: () => {
|
||||||
@ -96,7 +93,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [issueRef?.current, canDrag, issueId, groupId, dragHandleRef?.current, setIsCurrentBlockDragging]);
|
}, [canDrag, issueId, groupId, setIsCurrentBlockDragging]);
|
||||||
|
|
||||||
if (!issue) return null;
|
if (!issue) return null;
|
||||||
|
|
||||||
@ -135,20 +132,19 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
"bg-custom-background-80": isCurrentBlockDragging,
|
"bg-custom-background-80": isCurrentBlockDragging,
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
|
onDragStart={() => {
|
||||||
|
if (!canDrag) {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.WARNING,
|
||||||
|
title: "Cannot move issue",
|
||||||
|
message: "Drag and drop is disabled for the current grouping",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex w-full truncate">
|
<div className="flex w-full truncate">
|
||||||
<div className="flex flex-grow items-center gap-3 truncate">
|
<div className="flex flex-grow items-center gap-1.5 truncate">
|
||||||
<div className="flex items-center gap-0.5">
|
<div className="flex items-center gap-2" style={isSubIssue ? { marginLeft } : {}}>
|
||||||
{/* drag handle */}
|
|
||||||
<div className="size-4 flex items-center group/drag-handle">
|
|
||||||
<DragHandle
|
|
||||||
ref={dragHandleRef}
|
|
||||||
disabled={!canDrag}
|
|
||||||
className={cn("opacity-0 group-hover/drag-handle:opacity-100", {
|
|
||||||
"opacity-100": isCurrentBlockDragging,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/* select checkbox */}
|
{/* select checkbox */}
|
||||||
{projectId && canEditIssueProperties && (
|
{projectId && canEditIssueProperties && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -177,8 +173,14 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
{displayProperties && displayProperties?.key && (
|
||||||
|
<div className="flex-shrink-0 text-xs font-medium text-custom-text-300">
|
||||||
|
{projectIdentifier}-{issue.sequence_id}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* sub-issues chevron */}
|
{/* sub-issues chevron */}
|
||||||
<div className="size-4 grid place-items-center flex-shrink-0" style={isSubIssue ? { marginLeft } : {}}>
|
<div className="size-4 grid place-items-center flex-shrink-0">
|
||||||
{subIssuesCount > 0 && (
|
{subIssuesCount > 0 && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -194,11 +196,6 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{displayProperties && displayProperties?.key && (
|
|
||||||
<div className="flex-shrink-0 text-xs font-medium text-custom-text-300">
|
|
||||||
{projectIdentifier}-{issue.sequence_id}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{issue?.tempId !== undefined && (
|
{issue?.tempId !== undefined && (
|
||||||
<div className="absolute left-0 top-0 z-[99999] h-full w-full animate-pulse bg-custom-background-100/20" />
|
<div className="absolute left-0 top-0 z-[99999] h-full w-full animate-pulse bg-custom-background-100/20" />
|
||||||
@ -206,7 +203,12 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{issue?.is_draft ? (
|
{issue?.is_draft ? (
|
||||||
<Tooltip tooltipContent={issue.name} isMobile={isMobile} position="top-left">
|
<Tooltip
|
||||||
|
tooltipContent={issue.name}
|
||||||
|
isMobile={isMobile}
|
||||||
|
position="top-left"
|
||||||
|
disabled={isCurrentBlockDragging}
|
||||||
|
>
|
||||||
<p className="truncate">{issue.name}</p>
|
<p className="truncate">{issue.name}</p>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
|
@ -83,7 +83,7 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="group/list-header relative w-full flex-shrink-0 flex items-center gap-2.5 py-1.5 pl-3.5">
|
<div className="group/list-header relative w-full flex-shrink-0 flex items-center gap-2 py-1.5">
|
||||||
{canSelectIssues && (
|
{canSelectIssues && (
|
||||||
<div className="flex-shrink-0 flex items-center w-3.5">
|
<div className="flex-shrink-0 flex items-center w-3.5">
|
||||||
<MultipleSelectGroupAction
|
<MultipleSelectGroupAction
|
||||||
@ -98,7 +98,7 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex-shrink-0 grid place-items-center overflow-hidden pl-3">
|
<div className="flex-shrink-0 grid place-items-center overflow-hidden">
|
||||||
{icon ?? <CircleDashed className="size-3.5" strokeWidth={2} />}
|
{icon ?? <CircleDashed className="size-3.5" strokeWidth={2} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ export const ListGroup = observer((props: Props) => {
|
|||||||
"border-custom-error-200": isDraggingOverColumn && !!group.isDropDisabled,
|
"border-custom-error-200": isDraggingOverColumn && !!group.isDropDisabled,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 px-3 py-1">
|
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pl-2 pr-3 py-1">
|
||||||
<HeaderGroupByCard
|
<HeaderGroupByCard
|
||||||
groupID={group.id}
|
groupID={group.id}
|
||||||
icon={group.icon}
|
icon={group.icon}
|
||||||
|
@ -152,7 +152,7 @@ export const ListQuickAddIssueForm: FC<IListQuickAddIssueForm> = observer((props
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="flex w-full cursor-pointer items-center gap-2.5 p-6 py-3 text-custom-text-350 hover:text-custom-text-300"
|
className="flex w-full cursor-pointer items-center gap-2 px-2 py-3 text-custom-text-350 hover:text-custom-text-300"
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
||||||
|
Loading…
Reference in New Issue
Block a user