[WEB-1004] feat: Pragmatic dnd implementation for Kanban (#4189)
* Pragmatic drag and drop implmentation of Kanban * refactor pragmatic dnd implementation and fix bugs * fix dnd for modules, cycles, draft and project views
This commit is contained in:
parent
384624a21b
commit
7a21855ab6
22 changed files with 756 additions and 377 deletions
|
|
@ -1,6 +1,8 @@
|
|||
import { MutableRefObject } from "react";
|
||||
import { Droppable } from "@hello-pangea/dnd";
|
||||
// hooks
|
||||
import { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
||||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
||||
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
||||
//types
|
||||
import {
|
||||
TGroupedIssues,
|
||||
TIssue,
|
||||
|
|
@ -8,10 +10,14 @@ import {
|
|||
IIssueMap,
|
||||
TSubGroupedIssues,
|
||||
TUnGroupedIssues,
|
||||
TIssueGroupByOptions,
|
||||
} from "@plane/types";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useProjectState } from "@/hooks/store";
|
||||
//components
|
||||
//types
|
||||
import { KanbanDropLocation, getSourceFromDropPayload, getDestinationFromDropPayload } from "./utils";
|
||||
import { KanbanIssueBlocksList, KanBanQuickAddIssueForm } from ".";
|
||||
|
||||
interface IKanbanGroup {
|
||||
|
|
@ -20,8 +26,8 @@ interface IKanbanGroup {
|
|||
peekIssueId?: string;
|
||||
issueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
sub_group_by: string | null;
|
||||
group_by: string | null;
|
||||
sub_group_by: TIssueGroupByOptions | undefined;
|
||||
group_by: TIssueGroupByOptions | undefined;
|
||||
sub_group_id: string;
|
||||
isDragDisabled: boolean;
|
||||
updateIssue: ((projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
|
||||
|
|
@ -38,7 +44,7 @@ interface IKanbanGroup {
|
|||
canEditProperties: (projectId: string | undefined) => boolean;
|
||||
groupByVisibilityToggle?: boolean;
|
||||
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
||||
isDragStarted?: boolean;
|
||||
handleOnDrop: (source: KanbanDropLocation, destination: KanbanDropLocation) => Promise<void>;
|
||||
}
|
||||
|
||||
export const KanbanGroup = (props: IKanbanGroup) => {
|
||||
|
|
@ -60,14 +66,53 @@ export const KanbanGroup = (props: IKanbanGroup) => {
|
|||
quickAddCallback,
|
||||
viewId,
|
||||
scrollableContainerRef,
|
||||
isDragStarted,
|
||||
handleOnDrop,
|
||||
} = props;
|
||||
// hooks
|
||||
const projectState = useProjectState();
|
||||
|
||||
const [isDraggingOverColumn, setIsDraggingOverColumn] = useState(false);
|
||||
|
||||
const columnRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Enable Kanban Columns as Drop Targets
|
||||
useEffect(() => {
|
||||
const element = columnRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
return combine(
|
||||
dropTargetForElements({
|
||||
element,
|
||||
getData: () => ({ groupId, subGroupId: sub_group_id, columnId: `${groupId}__${sub_group_id}`, type: "COLUMN" }),
|
||||
onDragEnter: () => {
|
||||
setIsDraggingOverColumn(true);
|
||||
},
|
||||
onDragLeave: () => {
|
||||
setIsDraggingOverColumn(false);
|
||||
},
|
||||
onDragStart: () => {
|
||||
setIsDraggingOverColumn(true);
|
||||
},
|
||||
onDrop: (payload) => {
|
||||
setIsDraggingOverColumn(false);
|
||||
const source = getSourceFromDropPayload(payload);
|
||||
const destination = getDestinationFromDropPayload(payload);
|
||||
|
||||
if (!source || !destination) return;
|
||||
|
||||
handleOnDrop(source, destination);
|
||||
},
|
||||
}),
|
||||
autoScrollForElements({
|
||||
element,
|
||||
})
|
||||
);
|
||||
}, [columnRef?.current, groupId, sub_group_id, setIsDraggingOverColumn]);
|
||||
|
||||
const prePopulateQuickAddData = (
|
||||
groupByKey: string | null,
|
||||
subGroupByKey: string | null,
|
||||
groupByKey: string | undefined,
|
||||
subGroupByKey: string | undefined | null,
|
||||
groupValue: string,
|
||||
subGroupValue: string
|
||||
) => {
|
||||
|
|
@ -118,48 +163,43 @@ export const KanbanGroup = (props: IKanbanGroup) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={`relative w-full h-full transition-all`}>
|
||||
<Droppable droppableId={`${groupId}__${sub_group_id}`}>
|
||||
{(provided: any, snapshot: any) => (
|
||||
<div
|
||||
className={`relative h-full transition-all ${snapshot.isDraggingOver ? `bg-custom-background-80` : ``}`}
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
<KanbanIssueBlocksList
|
||||
sub_group_id={sub_group_id}
|
||||
columnId={groupId}
|
||||
issuesMap={issuesMap}
|
||||
peekIssueId={peekIssueId}
|
||||
issueIds={(issueIds as TGroupedIssues)?.[groupId] || []}
|
||||
displayProperties={displayProperties}
|
||||
isDragDisabled={isDragDisabled}
|
||||
updateIssue={updateIssue}
|
||||
quickActions={quickActions}
|
||||
canEditProperties={canEditProperties}
|
||||
scrollableContainerRef={scrollableContainerRef}
|
||||
isDragStarted={isDragStarted}
|
||||
/>
|
||||
<div
|
||||
id={`${groupId}__${sub_group_id}`}
|
||||
className={cn(
|
||||
"relative h-full transition-all",
|
||||
{ "bg-custom-background-80": isDraggingOverColumn },
|
||||
{ "vertical-scrollbar scrollbar-md": !sub_group_by }
|
||||
)}
|
||||
ref={columnRef}
|
||||
>
|
||||
<KanbanIssueBlocksList
|
||||
sub_group_id={sub_group_id}
|
||||
columnId={groupId}
|
||||
issuesMap={issuesMap}
|
||||
peekIssueId={peekIssueId}
|
||||
issueIds={(issueIds as TGroupedIssues)?.[groupId] || []}
|
||||
displayProperties={displayProperties}
|
||||
isDragDisabled={isDragDisabled}
|
||||
updateIssue={updateIssue}
|
||||
quickActions={quickActions}
|
||||
canEditProperties={canEditProperties}
|
||||
scrollableContainerRef={scrollableContainerRef}
|
||||
/>
|
||||
|
||||
{provided.placeholder}
|
||||
|
||||
{enableQuickIssueCreate && !disableIssueCreation && (
|
||||
<div className="w-full bg-custom-background-90 py-0.5 sticky bottom-0">
|
||||
<KanBanQuickAddIssueForm
|
||||
formKey="name"
|
||||
groupId={groupId}
|
||||
subGroupId={sub_group_id}
|
||||
prePopulatedData={{
|
||||
...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)),
|
||||
}}
|
||||
quickAddCallback={quickAddCallback}
|
||||
viewId={viewId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
{enableQuickIssueCreate && !disableIssueCreation && (
|
||||
<div className="w-full bg-custom-background-90 py-0.5 sticky bottom-0">
|
||||
<KanBanQuickAddIssueForm
|
||||
formKey="name"
|
||||
groupId={groupId}
|
||||
subGroupId={sub_group_id}
|
||||
prePopulatedData={{
|
||||
...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)),
|
||||
}}
|
||||
quickAddCallback={quickAddCallback}
|
||||
viewId={viewId}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue